]> git.saurik.com Git - apple/network_cmds.git/blob - ifconfig.tproj/ifbond.c
network_cmds-543.50.4.tar.gz
[apple/network_cmds.git] / ifconfig.tproj / ifbond.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 /*
24 * ifbond.c
25 * - add and remove interfaces from a bond interface
26 */
27
28 /*
29 * Modification History:
30 *
31 * July 14, 2004 Dieter Siegmund (dieter@apple.com)
32 * - created
33 */
34
35 #include <sys/param.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
38
39 #include <stdlib.h>
40 #include <unistd.h>
41
42 #include <net/ethernet.h>
43 #include <net/if.h>
44 #include <net/if_var.h>
45 #include <net/if_bond_var.h>
46
47 #include <net/route.h>
48
49 #include <ctype.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <err.h>
55 #include <errno.h>
56
57 #include "ifconfig.h"
58 extern int bond_details;
59
60 #define EA_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
61 #define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
62 #define EA_LIST(ea) EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5)
63
64 static __inline__ const char *
65 selected_state_string(u_char s)
66 {
67 static const char * names[] = { "unselected", "selected", "standby" };
68
69 if (s <= IF_BOND_STATUS_SELECTED_STATE_STANDBY) {
70 return (names[s]);
71 }
72 return ("<unknown>");
73 }
74
75 static void
76 bond_print_details(struct if_bond_status * ibs_p, int count)
77
78 {
79 int i;
80 struct if_bond_status * scan_p = ibs_p;
81
82 for (i = 0; i < count; i++, scan_p++) {
83 struct if_bond_partner_state * ps;
84 ps = &scan_p->ibs_partner_state;
85 printf("\tbond interface: %s priority: 0x%04x "
86 "state: 0x%02x partner system: 0x%04x,"
87 EA_FORMAT " "
88 "key: 0x%04x port: 0x%04x priority: 0x%04x "
89 "state: 0x%02x\n",
90 scan_p->ibs_if_name, scan_p->ibs_port_priority,
91 scan_p->ibs_state, ps->ibps_system_priority,
92 EA_LIST(&ps->ibps_system), ps->ibps_key,
93 ps->ibps_port, ps->ibps_port_priority,
94 ps->ibps_state);
95 }
96 return;
97 }
98
99 void
100 bond_status(int s)
101 {
102 int i;
103 struct if_bond_req ibr;
104 struct if_bond_status * ibs_p;
105 struct if_bond_status_req * ibsr_p;
106 char mode_buf[16];
107 const char * mode_str;
108
109 bzero((char *)&ibr, sizeof(ibr));
110 ibr.ibr_op = IF_BOND_OP_GET_STATUS;
111 ibsr_p = &ibr.ibr_ibru.ibru_status;
112 ibsr_p->ibsr_version = IF_BOND_STATUS_REQ_VERSION;
113 ifr.ifr_data = (caddr_t)&ibr;
114
115 /* how many of them are there? */
116 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
117 return;
118 }
119 switch (ibsr_p->ibsr_mode) {
120 case IF_BOND_MODE_LACP:
121 mode_str = "lacp";
122 break;
123 case IF_BOND_MODE_STATIC:
124 mode_str = "static";
125 break;
126 default:
127 snprintf(mode_buf, sizeof(mode_buf), "%d", ibsr_p->ibsr_mode);
128 mode_str = mode_buf;
129 break;
130 }
131 if (ibsr_p->ibsr_total == 0) {
132 if (bond_details) {
133 printf("\tbond mode: %s\n"
134 "\tbond key: 0x%04x interfaces: <none>",
135 mode_str, ibsr_p->ibsr_key);
136 }
137 else {
138 printf("\tbond interfaces: <none>\n");
139 }
140 return;
141 }
142 ibsr_p->ibsr_buffer
143 = (char *)malloc(sizeof(struct if_bond_status)
144 * ibsr_p->ibsr_total);
145 ibsr_p->ibsr_count = ibsr_p->ibsr_total;
146
147 /* get the list */
148 if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
149 goto done;
150 }
151 if (ibsr_p->ibsr_total > 0) {
152 if (bond_details) {
153 printf("\tbond mode: %s\n"
154 "\tbond key: 0x%04x interfaces:",
155 mode_str, ibsr_p->ibsr_key);
156 }
157 else {
158 printf("\tbond interfaces:");
159 }
160 ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer;
161 for (i = 0; i < ibsr_p->ibsr_total; i++, ibs_p++) {
162 printf(" %s", ibs_p->ibs_if_name);
163 if (bond_details) {
164 u_char s = ibs_p->ibs_selected_state;
165 printf(" (%s)", selected_state_string(s));
166 }
167 }
168 printf("\n");
169 if (bond_details) {
170 bond_print_details((struct if_bond_status *)
171 ibsr_p->ibsr_buffer,
172 ibsr_p->ibsr_total);
173 }
174 }
175 else if (bond_details) {
176 printf("\tbond mode: %s\n"
177 "\tbond key: 0x%04x interfaces: <none>\n",
178 mode_str, ibsr_p->ibsr_key);
179 }
180 else {
181 printf("\tbond interfaces: <none>\n");
182 }
183
184 done:
185 free(ibsr_p->ibsr_buffer);
186 return;
187 }
188
189 static
190 DECL_CMD_FUNC(setbonddev, val, d)
191 {
192 struct if_bond_req ibr;
193
194 bzero((char *)&ibr, sizeof(ibr));
195 if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name,
196 sizeof(ibr.ibr_ibru.ibru_if_name),
197 "%s", val) >= IFNAMSIZ) {
198 errx(1, "interface name too long");
199 }
200 ibr.ibr_op = IF_BOND_OP_ADD_INTERFACE;
201 ifr.ifr_data = (caddr_t)&ibr;
202 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1)
203 err(1, "SIOCSIFBOND add interface");
204
205 return;
206 }
207
208 static
209 DECL_CMD_FUNC(unsetbonddev, val, d)
210 {
211 struct if_bond_req ibr;
212
213 bzero((char *)&ibr, sizeof(ibr));
214 if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name,
215 sizeof(ibr.ibr_ibru.ibru_if_name),
216 "%s", val) >= IFNAMSIZ) {
217 errx(1, "interface name too long");
218 }
219 ibr.ibr_op = IF_BOND_OP_REMOVE_INTERFACE;
220 ifr.ifr_data = (caddr_t)&ibr;
221 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1)
222 err(1, "SIOCSIFBOND remove interface");
223
224 return;
225 }
226
227 static
228 DECL_CMD_FUNC(setbondmode, val, d)
229 {
230 struct if_bond_req ibr;
231 int mode;
232
233 if (strcmp(val, "lacp") == 0) {
234 mode = IF_BOND_MODE_LACP;
235 }
236 else if (strcmp(val, "static") == 0) {
237 mode = IF_BOND_MODE_STATIC;
238 }
239 else {
240 mode = strtoul(val, NULL, 0);
241 if (errno != 0) {
242 errx(1, "invalid mode value "
243 "(must be either \"lacp\" or \"static\")");
244 }
245 }
246
247 bzero((char *)&ibr, sizeof(ibr));
248 if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name,
249 sizeof(ibr.ibr_ibru.ibru_if_name),
250 "%s", val) >= IFNAMSIZ) {
251 errx(1, "interface name too long");
252 }
253 ibr.ibr_op = IF_BOND_OP_SET_MODE;
254 ibr.ibr_ibru.ibru_int_val = mode;
255 ifr.ifr_data = (caddr_t)&ibr;
256 if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1)
257 err(1, "SIOCSIFBOND set mode");
258
259 return;
260 }
261
262 static struct cmd bond_cmds[] = {
263 DEF_CLONE_CMD_ARG("bonddev", setbonddev),
264 DEF_CLONE_CMD_ARG("-bonddev", unsetbonddev),
265 DEF_CMD_ARG("bondmode", setbondmode),
266 };
267 static struct afswtch af_bond = {
268 .af_name = "af_bond",
269 .af_af = AF_UNSPEC,
270 .af_other_status = bond_status,
271 };
272
273 static __constructor void
274 bond_ctor(void)
275 {
276 #define N(a) (sizeof(a) / sizeof(a[0]))
277 int i;
278
279 for (i = 0; i < N(bond_cmds); i++)
280 cmd_register(&bond_cmds[i]);
281 af_register(&af_bond);
282 #undef N
283 }
284