Root/
1 | /* Mode: C; |
2 | * ifenslave.c: Configure network interfaces for parallel routing. |
3 | * |
4 | * This program controls the Linux implementation of running multiple |
5 | * network interfaces in parallel. |
6 | * |
7 | * Author: Donald Becker <becker@cesdis.gsfc.nasa.gov> |
8 | * Copyright 1994-1996 Donald Becker |
9 | * |
10 | * This program is free software; you can redistribute it |
11 | * and/or modify it under the terms of the GNU General Public |
12 | * License as published by the Free Software Foundation. |
13 | * |
14 | * The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O |
15 | * Center of Excellence in Space Data and Information Sciences |
16 | * Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 |
17 | * |
18 | * Changes : |
19 | * - 2000/10/02 Willy Tarreau <willy at meta-x.org> : |
20 | * - few fixes. Master's MAC address is now correctly taken from |
21 | * the first device when not previously set ; |
22 | * - detach support : call BOND_RELEASE to detach an enslaved interface. |
23 | * - give a mini-howto from command-line help : # ifenslave -h |
24 | * |
25 | * - 2001/02/16 Chad N. Tindel <ctindel at ieee dot org> : |
26 | * - Master is now brought down before setting the MAC address. In |
27 | * the 2.4 kernel you can't change the MAC address while the device is |
28 | * up because you get EBUSY. |
29 | * |
30 | * - 2001/09/13 Takao Indoh <indou dot takao at jp dot fujitsu dot com> |
31 | * - Added the ability to change the active interface on a mode 1 bond |
32 | * at runtime. |
33 | * |
34 | * - 2001/10/23 Chad N. Tindel <ctindel at ieee dot org> : |
35 | * - No longer set the MAC address of the master. The bond device will |
36 | * take care of this itself |
37 | * - Try the SIOC*** versions of the bonding ioctls before using the |
38 | * old versions |
39 | * - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> : |
40 | * - ifr2.ifr_flags was not initialized in the hwaddr_notset case, |
41 | * SIOCGIFFLAGS now called before hwaddr_notset test |
42 | * |
43 | * - 2002/10/31 Tony Cureington <tony.cureington * hp_com> : |
44 | * - If the master does not have a hardware address when the first slave |
45 | * is enslaved, the master is assigned the hardware address of that |
46 | * slave - there is a comment in bonding.c stating "ifenslave takes |
47 | * care of this now." This corrects the problem of slaves having |
48 | * different hardware addresses in active-backup mode when |
49 | * multiple interfaces are specified on a single ifenslave command |
50 | * (ifenslave bond0 eth0 eth1). |
51 | * |
52 | * - 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and |
53 | * Shmulik Hen <shmulik.hen at intel dot com> |
54 | * - Moved setting the slave's mac address and openning it, from |
55 | * the application to the driver. This enables support of modes |
56 | * that need to use the unique mac address of each slave. |
57 | * The driver also takes care of closing the slave and restoring its |
58 | * original mac address upon release. |
59 | * In addition, block possibility of enslaving before the master is up. |
60 | * This prevents putting the system in an undefined state. |
61 | * |
62 | * - 2003/05/01 - Amir Noam <amir.noam at intel dot com> |
63 | * - Added ABI version control to restore compatibility between |
64 | * new/old ifenslave and new/old bonding. |
65 | * - Prevent adding an adapter that is already a slave. |
66 | * Fixes the problem of stalling the transmission and leaving |
67 | * the slave in a down state. |
68 | * |
69 | * - 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com> |
70 | * - Prevent enslaving if the bond device is down. |
71 | * Fixes the problem of leaving the system in unstable state and |
72 | * halting when trying to remove the module. |
73 | * - Close socket on all abnormal exists. |
74 | * - Add versioning scheme that follows that of the bonding driver. |
75 | * current version is 1.0.0 as a base line. |
76 | * |
77 | * - 2003/05/22 - Jay Vosburgh <fubar at us dot ibm dot com> |
78 | * - ifenslave -c was broken; it's now fixed |
79 | * - Fixed problem with routes vanishing from master during enslave |
80 | * processing. |
81 | * |
82 | * - 2003/05/27 - Amir Noam <amir.noam at intel dot com> |
83 | * - Fix backward compatibility issues: |
84 | * For drivers not using ABI versions, slave was set down while |
85 | * it should be left up before enslaving. |
86 | * Also, master was not set down and the default set_mac_address() |
87 | * would fail and generate an error message in the system log. |
88 | * - For opt_c: slave should not be set to the master's setting |
89 | * while it is running. It was already set during enslave. To |
90 | * simplify things, it is now handled separately. |
91 | * |
92 | * - 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com> |
93 | * - Code cleanup and style changes |
94 | * set version to 1.1.0 |
95 | */ |
96 | |
97 | #define APP_VERSION "1.1.0" |
98 | #define APP_RELDATE "December 1, 2003" |
99 | #define APP_NAME "ifenslave" |
100 | |
101 | static char *version = |
102 | APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ")\n" |
103 | "o Donald Becker (becker@cesdis.gsfc.nasa.gov).\n" |
104 | "o Detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" |
105 | "o 2.4 kernel support added on 2001/02/16 by Chad N. Tindel\n" |
106 | " (ctindel at ieee dot org).\n"; |
107 | |
108 | static const char *usage_msg = |
109 | "Usage: ifenslave [-f] <master-if> <slave-if> [<slave-if>...]\n" |
110 | " ifenslave -d <master-if> <slave-if> [<slave-if>...]\n" |
111 | " ifenslave -c <master-if> <slave-if>\n" |
112 | " ifenslave --help\n"; |
113 | |
114 | static const char *help_msg = |
115 | "\n" |
116 | " To create a bond device, simply follow these three steps :\n" |
117 | " - ensure that the required drivers are properly loaded :\n" |
118 | " # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n" |
119 | " - assign an IP address to the bond device :\n" |
120 | " # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\n" |
121 | " - attach all the interfaces you need to the bond device :\n" |
122 | " # ifenslave [{-f|--force}] bond0 eth0 [eth1 [eth2]...]\n" |
123 | " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" |
124 | " interfaces attached AFTER this assignment will get the same MAC addr.\n" |
125 | " (except for ALB/TLB modes)\n" |
126 | "\n" |
127 | " To set the bond device down and automatically release all the slaves :\n" |
128 | " # ifconfig bond0 down\n" |
129 | "\n" |
130 | " To detach a dead interface without setting the bond device down :\n" |
131 | " # ifenslave {-d|--detach} bond0 eth0 [eth1 [eth2]...]\n" |
132 | "\n" |
133 | " To change active slave :\n" |
134 | " # ifenslave {-c|--change-active} bond0 eth0\n" |
135 | "\n" |
136 | " To show master interface info\n" |
137 | " # ifenslave bond0\n" |
138 | "\n" |
139 | " To show all interfaces info\n" |
140 | " # ifenslave {-a|--all-interfaces}\n" |
141 | "\n" |
142 | " To be more verbose\n" |
143 | " # ifenslave {-v|--verbose} ...\n" |
144 | "\n" |
145 | " # ifenslave {-u|--usage} Show usage\n" |
146 | " # ifenslave {-V|--version} Show version\n" |
147 | " # ifenslave {-h|--help} This message\n" |
148 | "\n"; |
149 | |
150 | #include <unistd.h> |
151 | #include <stdlib.h> |
152 | #include <stdio.h> |
153 | #include <ctype.h> |
154 | #include <string.h> |
155 | #include <errno.h> |
156 | #include <fcntl.h> |
157 | #include <getopt.h> |
158 | #include <sys/types.h> |
159 | #include <sys/socket.h> |
160 | #include <sys/ioctl.h> |
161 | #include <linux/if.h> |
162 | #include <net/if_arp.h> |
163 | #include <linux/if_ether.h> |
164 | #include <linux/if_bonding.h> |
165 | #include <linux/sockios.h> |
166 | |
167 | typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */ |
168 | typedef __uint32_t u32; /* ditto */ |
169 | typedef __uint16_t u16; /* ditto */ |
170 | typedef __uint8_t u8; /* ditto */ |
171 | #include <linux/ethtool.h> |
172 | |
173 | struct option longopts[] = { |
174 | /* { name has_arg *flag val } */ |
175 | {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ |
176 | {"change-active", 0, 0, 'c'}, /* Change the active slave. */ |
177 | {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ |
178 | {"force", 0, 0, 'f'}, /* Force the operation. */ |
179 | {"help", 0, 0, 'h'}, /* Give help */ |
180 | {"usage", 0, 0, 'u'}, /* Give usage */ |
181 | {"verbose", 0, 0, 'v'}, /* Report each action taken. */ |
182 | {"version", 0, 0, 'V'}, /* Emit version information. */ |
183 | { 0, 0, 0, 0} |
184 | }; |
185 | |
186 | /* Command-line flags. */ |
187 | unsigned int |
188 | opt_a = 0, /* Show-all-interfaces flag. */ |
189 | opt_c = 0, /* Change-active-slave flag. */ |
190 | opt_d = 0, /* Detach a slave interface. */ |
191 | opt_f = 0, /* Force the operation. */ |
192 | opt_h = 0, /* Help */ |
193 | opt_u = 0, /* Usage */ |
194 | opt_v = 0, /* Verbose flag. */ |
195 | opt_V = 0; /* Version */ |
196 | |
197 | int skfd = -1; /* AF_INET socket for ioctl() calls.*/ |
198 | int abi_ver = 0; /* userland - kernel ABI version */ |
199 | int hwaddr_set = 0; /* Master's hwaddr is set */ |
200 | int saved_errno; |
201 | |
202 | struct ifreq master_mtu, master_flags, master_hwaddr; |
203 | struct ifreq slave_mtu, slave_flags, slave_hwaddr; |
204 | |
205 | struct dev_ifr { |
206 | struct ifreq *req_ifr; |
207 | char *req_name; |
208 | int req_type; |
209 | }; |
210 | |
211 | struct dev_ifr master_ifra[] = { |
212 | {&master_mtu, "SIOCGIFMTU", SIOCGIFMTU}, |
213 | {&master_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, |
214 | {&master_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, |
215 | {NULL, "", 0} |
216 | }; |
217 | |
218 | struct dev_ifr slave_ifra[] = { |
219 | {&slave_mtu, "SIOCGIFMTU", SIOCGIFMTU}, |
220 | {&slave_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, |
221 | {&slave_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, |
222 | {NULL, "", 0} |
223 | }; |
224 | |
225 | static void if_print(char *ifname); |
226 | static int get_drv_info(char *master_ifname); |
227 | static int get_if_settings(char *ifname, struct dev_ifr ifra[]); |
228 | static int get_slave_flags(char *slave_ifname); |
229 | static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr); |
230 | static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr); |
231 | static int set_slave_mtu(char *slave_ifname, int mtu); |
232 | static int set_if_flags(char *ifname, short flags); |
233 | static int set_if_up(char *ifname, short flags); |
234 | static int set_if_down(char *ifname, short flags); |
235 | static int clear_if_addr(char *ifname); |
236 | static int set_if_addr(char *master_ifname, char *slave_ifname); |
237 | static int change_active(char *master_ifname, char *slave_ifname); |
238 | static int enslave(char *master_ifname, char *slave_ifname); |
239 | static int release(char *master_ifname, char *slave_ifname); |
240 | #define v_print(fmt, args...) \ |
241 | if (opt_v) \ |
242 | fprintf(stderr, fmt, ## args ) |
243 | |
244 | int main(int argc, char *argv[]) |
245 | { |
246 | char **spp, *master_ifname, *slave_ifname; |
247 | int c, i, rv; |
248 | int res = 0; |
249 | int exclusive = 0; |
250 | |
251 | while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) { |
252 | switch (c) { |
253 | case 'a': opt_a++; exclusive++; break; |
254 | case 'c': opt_c++; exclusive++; break; |
255 | case 'd': opt_d++; exclusive++; break; |
256 | case 'f': opt_f++; exclusive++; break; |
257 | case 'h': opt_h++; exclusive++; break; |
258 | case 'u': opt_u++; exclusive++; break; |
259 | case 'v': opt_v++; break; |
260 | case 'V': opt_V++; exclusive++; break; |
261 | |
262 | case '?': |
263 | fprintf(stderr, usage_msg); |
264 | res = 2; |
265 | goto out; |
266 | } |
267 | } |
268 | |
269 | /* options check */ |
270 | if (exclusive > 1) { |
271 | fprintf(stderr, usage_msg); |
272 | res = 2; |
273 | goto out; |
274 | } |
275 | |
276 | if (opt_v || opt_V) { |
277 | printf(version); |
278 | if (opt_V) { |
279 | res = 0; |
280 | goto out; |
281 | } |
282 | } |
283 | |
284 | if (opt_u) { |
285 | printf(usage_msg); |
286 | res = 0; |
287 | goto out; |
288 | } |
289 | |
290 | if (opt_h) { |
291 | printf(usage_msg); |
292 | printf(help_msg); |
293 | res = 0; |
294 | goto out; |
295 | } |
296 | |
297 | /* Open a basic socket */ |
298 | if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
299 | perror("socket"); |
300 | res = 1; |
301 | goto out; |
302 | } |
303 | |
304 | if (opt_a) { |
305 | if (optind == argc) { |
306 | /* No remaining args */ |
307 | /* show all interfaces */ |
308 | if_print((char *)NULL); |
309 | goto out; |
310 | } else { |
311 | /* Just show usage */ |
312 | fprintf(stderr, usage_msg); |
313 | res = 2; |
314 | goto out; |
315 | } |
316 | } |
317 | |
318 | /* Copy the interface name */ |
319 | spp = argv + optind; |
320 | master_ifname = *spp++; |
321 | |
322 | if (master_ifname == NULL) { |
323 | fprintf(stderr, usage_msg); |
324 | res = 2; |
325 | goto out; |
326 | } |
327 | |
328 | /* exchange abi version with bonding module */ |
329 | res = get_drv_info(master_ifname); |
330 | if (res) { |
331 | fprintf(stderr, |
332 | "Master '%s': Error: handshake with driver failed. " |
333 | "Aborting\n", |
334 | master_ifname); |
335 | goto out; |
336 | } |
337 | |
338 | slave_ifname = *spp++; |
339 | |
340 | if (slave_ifname == NULL) { |
341 | if (opt_d || opt_c) { |
342 | fprintf(stderr, usage_msg); |
343 | res = 2; |
344 | goto out; |
345 | } |
346 | |
347 | /* A single arg means show the |
348 | * configuration for this interface |
349 | */ |
350 | if_print(master_ifname); |
351 | goto out; |
352 | } |
353 | |
354 | res = get_if_settings(master_ifname, master_ifra); |
355 | if (res) { |
356 | /* Probably a good reason not to go on */ |
357 | fprintf(stderr, |
358 | "Master '%s': Error: get settings failed: %s. " |
359 | "Aborting\n", |
360 | master_ifname, strerror(res)); |
361 | goto out; |
362 | } |
363 | |
364 | /* check if master is indeed a master; |
365 | * if not then fail any operation |
366 | */ |
367 | if (!(master_flags.ifr_flags & IFF_MASTER)) { |
368 | fprintf(stderr, |
369 | "Illegal operation; the specified interface '%s' " |
370 | "is not a master. Aborting\n", |
371 | master_ifname); |
372 | res = 1; |
373 | goto out; |
374 | } |
375 | |
376 | /* check if master is up; if not then fail any operation */ |
377 | if (!(master_flags.ifr_flags & IFF_UP)) { |
378 | fprintf(stderr, |
379 | "Illegal operation; the specified master interface " |
380 | "'%s' is not up.\n", |
381 | master_ifname); |
382 | res = 1; |
383 | goto out; |
384 | } |
385 | |
386 | /* Only for enslaving */ |
387 | if (!opt_c && !opt_d) { |
388 | sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family; |
389 | unsigned char *hwaddr = |
390 | (unsigned char *)master_hwaddr.ifr_hwaddr.sa_data; |
391 | |
392 | /* The family '1' is ARPHRD_ETHER for ethernet. */ |
393 | if (master_family != 1 && !opt_f) { |
394 | fprintf(stderr, |
395 | "Illegal operation: The specified master " |
396 | "interface '%s' is not ethernet-like.\n " |
397 | "This program is designed to work with " |
398 | "ethernet-like network interfaces.\n " |
399 | "Use the '-f' option to force the " |
400 | "operation.\n", |
401 | master_ifname); |
402 | res = 1; |
403 | goto out; |
404 | } |
405 | |
406 | /* Check master's hw addr */ |
407 | for (i = 0; i < 6; i++) { |
408 | if (hwaddr[i] != 0) { |
409 | hwaddr_set = 1; |
410 | break; |
411 | } |
412 | } |
413 | |
414 | if (hwaddr_set) { |
415 | v_print("current hardware address of master '%s' " |
416 | "is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " |
417 | "type %d\n", |
418 | master_ifname, |
419 | hwaddr[0], hwaddr[1], |
420 | hwaddr[2], hwaddr[3], |
421 | hwaddr[4], hwaddr[5], |
422 | master_family); |
423 | } |
424 | } |
425 | |
426 | /* Accepts only one slave */ |
427 | if (opt_c) { |
428 | /* change active slave */ |
429 | res = get_slave_flags(slave_ifname); |
430 | if (res) { |
431 | fprintf(stderr, |
432 | "Slave '%s': Error: get flags failed. " |
433 | "Aborting\n", |
434 | slave_ifname); |
435 | goto out; |
436 | } |
437 | res = change_active(master_ifname, slave_ifname); |
438 | if (res) { |
439 | fprintf(stderr, |
440 | "Master '%s', Slave '%s': Error: " |
441 | "Change active failed\n", |
442 | master_ifname, slave_ifname); |
443 | } |
444 | } else { |
445 | /* Accept multiple slaves */ |
446 | do { |
447 | if (opt_d) { |
448 | /* detach a slave interface from the master */ |
449 | rv = get_slave_flags(slave_ifname); |
450 | if (rv) { |
451 | /* Can't work with this slave. */ |
452 | /* remember the error and skip it*/ |
453 | fprintf(stderr, |
454 | "Slave '%s': Error: get flags " |
455 | "failed. Skipping\n", |
456 | slave_ifname); |
457 | res = rv; |
458 | continue; |
459 | } |
460 | rv = release(master_ifname, slave_ifname); |
461 | if (rv) { |
462 | fprintf(stderr, |
463 | "Master '%s', Slave '%s': Error: " |
464 | "Release failed\n", |
465 | master_ifname, slave_ifname); |
466 | res = rv; |
467 | } |
468 | } else { |
469 | /* attach a slave interface to the master */ |
470 | rv = get_if_settings(slave_ifname, slave_ifra); |
471 | if (rv) { |
472 | /* Can't work with this slave. */ |
473 | /* remember the error and skip it*/ |
474 | fprintf(stderr, |
475 | "Slave '%s': Error: get " |
476 | "settings failed: %s. " |
477 | "Skipping\n", |
478 | slave_ifname, strerror(rv)); |
479 | res = rv; |
480 | continue; |
481 | } |
482 | rv = enslave(master_ifname, slave_ifname); |
483 | if (rv) { |
484 | fprintf(stderr, |
485 | "Master '%s', Slave '%s': Error: " |
486 | "Enslave failed\n", |
487 | master_ifname, slave_ifname); |
488 | res = rv; |
489 | } |
490 | } |
491 | } while ((slave_ifname = *spp++) != NULL); |
492 | } |
493 | |
494 | out: |
495 | if (skfd >= 0) { |
496 | close(skfd); |
497 | } |
498 | |
499 | return res; |
500 | } |
501 | |
502 | static short mif_flags; |
503 | |
504 | /* Get the inteface configuration from the kernel. */ |
505 | static int if_getconfig(char *ifname) |
506 | { |
507 | struct ifreq ifr; |
508 | int metric, mtu; /* Parameters of the master interface. */ |
509 | struct sockaddr dstaddr, broadaddr, netmask; |
510 | unsigned char *hwaddr; |
511 | |
512 | strcpy(ifr.ifr_name, ifname); |
513 | if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) |
514 | return -1; |
515 | mif_flags = ifr.ifr_flags; |
516 | printf("The result of SIOCGIFFLAGS on %s is %x.\n", |
517 | ifname, ifr.ifr_flags); |
518 | |
519 | strcpy(ifr.ifr_name, ifname); |
520 | if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) |
521 | return -1; |
522 | printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n", |
523 | ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], |
524 | ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); |
525 | |
526 | strcpy(ifr.ifr_name, ifname); |
527 | if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) |
528 | return -1; |
529 | |
530 | /* Gotta convert from 'char' to unsigned for printf(). */ |
531 | hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; |
532 | printf("The result of SIOCGIFHWADDR is type %d " |
533 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", |
534 | ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], |
535 | hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); |
536 | |
537 | strcpy(ifr.ifr_name, ifname); |
538 | if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { |
539 | metric = 0; |
540 | } else |
541 | metric = ifr.ifr_metric; |
542 | |
543 | strcpy(ifr.ifr_name, ifname); |
544 | if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) |
545 | mtu = 0; |
546 | else |
547 | mtu = ifr.ifr_mtu; |
548 | |
549 | strcpy(ifr.ifr_name, ifname); |
550 | if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) { |
551 | memset(&dstaddr, 0, sizeof(struct sockaddr)); |
552 | } else |
553 | dstaddr = ifr.ifr_dstaddr; |
554 | |
555 | strcpy(ifr.ifr_name, ifname); |
556 | if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) { |
557 | memset(&broadaddr, 0, sizeof(struct sockaddr)); |
558 | } else |
559 | broadaddr = ifr.ifr_broadaddr; |
560 | |
561 | strcpy(ifr.ifr_name, ifname); |
562 | if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) { |
563 | memset(&netmask, 0, sizeof(struct sockaddr)); |
564 | } else |
565 | netmask = ifr.ifr_netmask; |
566 | |
567 | return 0; |
568 | } |
569 | |
570 | static void if_print(char *ifname) |
571 | { |
572 | char buff[1024]; |
573 | struct ifconf ifc; |
574 | struct ifreq *ifr; |
575 | int i; |
576 | |
577 | if (ifname == (char *)NULL) { |
578 | ifc.ifc_len = sizeof(buff); |
579 | ifc.ifc_buf = buff; |
580 | if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { |
581 | perror("SIOCGIFCONF failed"); |
582 | return; |
583 | } |
584 | |
585 | ifr = ifc.ifc_req; |
586 | for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { |
587 | if (if_getconfig(ifr->ifr_name) < 0) { |
588 | fprintf(stderr, |
589 | "%s: unknown interface.\n", |
590 | ifr->ifr_name); |
591 | continue; |
592 | } |
593 | |
594 | if (((mif_flags & IFF_UP) == 0) && !opt_a) continue; |
595 | /*ife_print(&ife);*/ |
596 | } |
597 | } else { |
598 | if (if_getconfig(ifname) < 0) { |
599 | fprintf(stderr, |
600 | "%s: unknown interface.\n", ifname); |
601 | } |
602 | } |
603 | } |
604 | |
605 | static int get_drv_info(char *master_ifname) |
606 | { |
607 | struct ifreq ifr; |
608 | struct ethtool_drvinfo info; |
609 | char *endptr; |
610 | |
611 | memset(&ifr, 0, sizeof(ifr)); |
612 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); |
613 | ifr.ifr_data = (caddr_t)&info; |
614 | |
615 | info.cmd = ETHTOOL_GDRVINFO; |
616 | strncpy(info.driver, "ifenslave", 32); |
617 | snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); |
618 | |
619 | if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) { |
620 | if (errno == EOPNOTSUPP) { |
621 | goto out; |
622 | } |
623 | |
624 | saved_errno = errno; |
625 | v_print("Master '%s': Error: get bonding info failed %s\n", |
626 | master_ifname, strerror(saved_errno)); |
627 | return 1; |
628 | } |
629 | |
630 | abi_ver = strtoul(info.fw_version, &endptr, 0); |
631 | if (*endptr) { |
632 | v_print("Master '%s': Error: got invalid string as an ABI " |
633 | "version from the bonding module\n", |
634 | master_ifname); |
635 | return 1; |
636 | } |
637 | |
638 | out: |
639 | v_print("ABI ver is %d\n", abi_ver); |
640 | |
641 | return 0; |
642 | } |
643 | |
644 | static int change_active(char *master_ifname, char *slave_ifname) |
645 | { |
646 | struct ifreq ifr; |
647 | int res = 0; |
648 | |
649 | if (!(slave_flags.ifr_flags & IFF_SLAVE)) { |
650 | fprintf(stderr, |
651 | "Illegal operation: The specified slave interface " |
652 | "'%s' is not a slave\n", |
653 | slave_ifname); |
654 | return 1; |
655 | } |
656 | |
657 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); |
658 | strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); |
659 | if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) && |
660 | (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) { |
661 | saved_errno = errno; |
662 | v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: " |
663 | "%s\n", |
664 | master_ifname, strerror(saved_errno)); |
665 | res = 1; |
666 | } |
667 | |
668 | return res; |
669 | } |
670 | |
671 | static int enslave(char *master_ifname, char *slave_ifname) |
672 | { |
673 | struct ifreq ifr; |
674 | int res = 0; |
675 | |
676 | if (slave_flags.ifr_flags & IFF_SLAVE) { |
677 | fprintf(stderr, |
678 | "Illegal operation: The specified slave interface " |
679 | "'%s' is already a slave\n", |
680 | slave_ifname); |
681 | return 1; |
682 | } |
683 | |
684 | res = set_if_down(slave_ifname, slave_flags.ifr_flags); |
685 | if (res) { |
686 | fprintf(stderr, |
687 | "Slave '%s': Error: bring interface down failed\n", |
688 | slave_ifname); |
689 | return res; |
690 | } |
691 | |
692 | if (abi_ver < 2) { |
693 | /* Older bonding versions would panic if the slave has no IP |
694 | * address, so get the IP setting from the master. |
695 | */ |
696 | set_if_addr(master_ifname, slave_ifname); |
697 | } else { |
698 | res = clear_if_addr(slave_ifname); |
699 | if (res) { |
700 | fprintf(stderr, |
701 | "Slave '%s': Error: clear address failed\n", |
702 | slave_ifname); |
703 | return res; |
704 | } |
705 | } |
706 | |
707 | if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) { |
708 | res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu); |
709 | if (res) { |
710 | fprintf(stderr, |
711 | "Slave '%s': Error: set MTU failed\n", |
712 | slave_ifname); |
713 | return res; |
714 | } |
715 | } |
716 | |
717 | if (hwaddr_set) { |
718 | /* Master already has an hwaddr |
719 | * so set it's hwaddr to the slave |
720 | */ |
721 | if (abi_ver < 1) { |
722 | /* The driver is using an old ABI, so |
723 | * the application sets the slave's |
724 | * hwaddr |
725 | */ |
726 | res = set_slave_hwaddr(slave_ifname, |
727 | &(master_hwaddr.ifr_hwaddr)); |
728 | if (res) { |
729 | fprintf(stderr, |
730 | "Slave '%s': Error: set hw address " |
731 | "failed\n", |
732 | slave_ifname); |
733 | goto undo_mtu; |
734 | } |
735 | |
736 | /* For old ABI the application needs to bring the |
737 | * slave back up |
738 | */ |
739 | res = set_if_up(slave_ifname, slave_flags.ifr_flags); |
740 | if (res) { |
741 | fprintf(stderr, |
742 | "Slave '%s': Error: bring interface " |
743 | "down failed\n", |
744 | slave_ifname); |
745 | goto undo_slave_mac; |
746 | } |
747 | } |
748 | /* The driver is using a new ABI, |
749 | * so the driver takes care of setting |
750 | * the slave's hwaddr and bringing |
751 | * it up again |
752 | */ |
753 | } else { |
754 | /* No hwaddr for master yet, so |
755 | * set the slave's hwaddr to it |
756 | */ |
757 | if (abi_ver < 1) { |
758 | /* For old ABI, the master needs to be |
759 | * down before setting it's hwaddr |
760 | */ |
761 | res = set_if_down(master_ifname, master_flags.ifr_flags); |
762 | if (res) { |
763 | fprintf(stderr, |
764 | "Master '%s': Error: bring interface " |
765 | "down failed\n", |
766 | master_ifname); |
767 | goto undo_mtu; |
768 | } |
769 | } |
770 | |
771 | res = set_master_hwaddr(master_ifname, |
772 | &(slave_hwaddr.ifr_hwaddr)); |
773 | if (res) { |
774 | fprintf(stderr, |
775 | "Master '%s': Error: set hw address " |
776 | "failed\n", |
777 | master_ifname); |
778 | goto undo_mtu; |
779 | } |
780 | |
781 | if (abi_ver < 1) { |
782 | /* For old ABI, bring the master |
783 | * back up |
784 | */ |
785 | res = set_if_up(master_ifname, master_flags.ifr_flags); |
786 | if (res) { |
787 | fprintf(stderr, |
788 | "Master '%s': Error: bring interface " |
789 | "up failed\n", |
790 | master_ifname); |
791 | goto undo_master_mac; |
792 | } |
793 | } |
794 | |
795 | hwaddr_set = 1; |
796 | } |
797 | |
798 | /* Do the real thing */ |
799 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); |
800 | strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); |
801 | if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) && |
802 | (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) { |
803 | saved_errno = errno; |
804 | v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n", |
805 | master_ifname, strerror(saved_errno)); |
806 | res = 1; |
807 | } |
808 | |
809 | if (res) { |
810 | goto undo_master_mac; |
811 | } |
812 | |
813 | return 0; |
814 | |
815 | /* rollback (best effort) */ |
816 | undo_master_mac: |
817 | set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr)); |
818 | hwaddr_set = 0; |
819 | goto undo_mtu; |
820 | undo_slave_mac: |
821 | set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr)); |
822 | undo_mtu: |
823 | set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu); |
824 | return res; |
825 | } |
826 | |
827 | static int release(char *master_ifname, char *slave_ifname) |
828 | { |
829 | struct ifreq ifr; |
830 | int res = 0; |
831 | |
832 | if (!(slave_flags.ifr_flags & IFF_SLAVE)) { |
833 | fprintf(stderr, |
834 | "Illegal operation: The specified slave interface " |
835 | "'%s' is not a slave\n", |
836 | slave_ifname); |
837 | return 1; |
838 | } |
839 | |
840 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); |
841 | strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); |
842 | if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) && |
843 | (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) { |
844 | saved_errno = errno; |
845 | v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n", |
846 | master_ifname, strerror(saved_errno)); |
847 | return 1; |
848 | } else if (abi_ver < 1) { |
849 | /* The driver is using an old ABI, so we'll set the interface |
850 | * down to avoid any conflicts due to same MAC/IP |
851 | */ |
852 | res = set_if_down(slave_ifname, slave_flags.ifr_flags); |
853 | if (res) { |
854 | fprintf(stderr, |
855 | "Slave '%s': Error: bring interface " |
856 | "down failed\n", |
857 | slave_ifname); |
858 | } |
859 | } |
860 | |
861 | /* set to default mtu */ |
862 | set_slave_mtu(slave_ifname, 1500); |
863 | |
864 | return res; |
865 | } |
866 | |
867 | static int get_if_settings(char *ifname, struct dev_ifr ifra[]) |
868 | { |
869 | int i; |
870 | int res = 0; |
871 | |
872 | for (i = 0; ifra[i].req_ifr; i++) { |
873 | strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ); |
874 | res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr); |
875 | if (res < 0) { |
876 | saved_errno = errno; |
877 | v_print("Interface '%s': Error: %s failed: %s\n", |
878 | ifname, ifra[i].req_name, |
879 | strerror(saved_errno)); |
880 | |
881 | return saved_errno; |
882 | } |
883 | } |
884 | |
885 | return 0; |
886 | } |
887 | |
888 | static int get_slave_flags(char *slave_ifname) |
889 | { |
890 | int res = 0; |
891 | |
892 | strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ); |
893 | res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags); |
894 | if (res < 0) { |
895 | saved_errno = errno; |
896 | v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n", |
897 | slave_ifname, strerror(saved_errno)); |
898 | } else { |
899 | v_print("Slave %s: flags %04X.\n", |
900 | slave_ifname, slave_flags.ifr_flags); |
901 | } |
902 | |
903 | return res; |
904 | } |
905 | |
906 | static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr) |
907 | { |
908 | unsigned char *addr = (unsigned char *)hwaddr->sa_data; |
909 | struct ifreq ifr; |
910 | int res = 0; |
911 | |
912 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); |
913 | memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); |
914 | res = ioctl(skfd, SIOCSIFHWADDR, &ifr); |
915 | if (res < 0) { |
916 | saved_errno = errno; |
917 | v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n", |
918 | master_ifname, strerror(saved_errno)); |
919 | return res; |
920 | } else { |
921 | v_print("Master '%s': hardware address set to " |
922 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", |
923 | master_ifname, addr[0], addr[1], addr[2], |
924 | addr[3], addr[4], addr[5]); |
925 | } |
926 | |
927 | return res; |
928 | } |
929 | |
930 | static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr) |
931 | { |
932 | unsigned char *addr = (unsigned char *)hwaddr->sa_data; |
933 | struct ifreq ifr; |
934 | int res = 0; |
935 | |
936 | strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); |
937 | memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); |
938 | res = ioctl(skfd, SIOCSIFHWADDR, &ifr); |
939 | if (res < 0) { |
940 | saved_errno = errno; |
941 | |
942 | v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n", |
943 | slave_ifname, strerror(saved_errno)); |
944 | |
945 | if (saved_errno == EBUSY) { |
946 | v_print(" The device is busy: it must be idle " |
947 | "before running this command.\n"); |
948 | } else if (saved_errno == EOPNOTSUPP) { |
949 | v_print(" The device does not support setting " |
950 | "the MAC address.\n" |
951 | " Your kernel likely does not support slave " |
952 | "devices.\n"); |
953 | } else if (saved_errno == EINVAL) { |
954 | v_print(" The device's address type does not match " |
955 | "the master's address type.\n"); |
956 | } |
957 | return res; |
958 | } else { |
959 | v_print("Slave '%s': hardware address set to " |
960 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", |
961 | slave_ifname, addr[0], addr[1], addr[2], |
962 | addr[3], addr[4], addr[5]); |
963 | } |
964 | |
965 | return res; |
966 | } |
967 | |
968 | static int set_slave_mtu(char *slave_ifname, int mtu) |
969 | { |
970 | struct ifreq ifr; |
971 | int res = 0; |
972 | |
973 | ifr.ifr_mtu = mtu; |
974 | strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); |
975 | |
976 | res = ioctl(skfd, SIOCSIFMTU, &ifr); |
977 | if (res < 0) { |
978 | saved_errno = errno; |
979 | v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n", |
980 | slave_ifname, strerror(saved_errno)); |
981 | } else { |
982 | v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu); |
983 | } |
984 | |
985 | return res; |
986 | } |
987 | |
988 | static int set_if_flags(char *ifname, short flags) |
989 | { |
990 | struct ifreq ifr; |
991 | int res = 0; |
992 | |
993 | ifr.ifr_flags = flags; |
994 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); |
995 | |
996 | res = ioctl(skfd, SIOCSIFFLAGS, &ifr); |
997 | if (res < 0) { |
998 | saved_errno = errno; |
999 | v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n", |
1000 | ifname, strerror(saved_errno)); |
1001 | } else { |
1002 | v_print("Interface '%s': flags set to %04X.\n", ifname, flags); |
1003 | } |
1004 | |
1005 | return res; |
1006 | } |
1007 | |
1008 | static int set_if_up(char *ifname, short flags) |
1009 | { |
1010 | return set_if_flags(ifname, flags | IFF_UP); |
1011 | } |
1012 | |
1013 | static int set_if_down(char *ifname, short flags) |
1014 | { |
1015 | return set_if_flags(ifname, flags & ~IFF_UP); |
1016 | } |
1017 | |
1018 | static int clear_if_addr(char *ifname) |
1019 | { |
1020 | struct ifreq ifr; |
1021 | int res = 0; |
1022 | |
1023 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); |
1024 | ifr.ifr_addr.sa_family = AF_INET; |
1025 | memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); |
1026 | |
1027 | res = ioctl(skfd, SIOCSIFADDR, &ifr); |
1028 | if (res < 0) { |
1029 | saved_errno = errno; |
1030 | v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n", |
1031 | ifname, strerror(saved_errno)); |
1032 | } else { |
1033 | v_print("Interface '%s': address cleared\n", ifname); |
1034 | } |
1035 | |
1036 | return res; |
1037 | } |
1038 | |
1039 | static int set_if_addr(char *master_ifname, char *slave_ifname) |
1040 | { |
1041 | struct ifreq ifr; |
1042 | int res; |
1043 | unsigned char *ipaddr; |
1044 | int i; |
1045 | struct { |
1046 | char *req_name; |
1047 | char *desc; |
1048 | int g_ioctl; |
1049 | int s_ioctl; |
1050 | } ifra[] = { |
1051 | {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR}, |
1052 | {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR}, |
1053 | {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR}, |
1054 | {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK}, |
1055 | {NULL, NULL, 0, 0}, |
1056 | }; |
1057 | |
1058 | for (i = 0; ifra[i].req_name; i++) { |
1059 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); |
1060 | res = ioctl(skfd, ifra[i].g_ioctl, &ifr); |
1061 | if (res < 0) { |
1062 | int saved_errno = errno; |
1063 | |
1064 | v_print("Interface '%s': Error: SIOCG%s failed: %s\n", |
1065 | master_ifname, ifra[i].req_name, |
1066 | strerror(saved_errno)); |
1067 | |
1068 | ifr.ifr_addr.sa_family = AF_INET; |
1069 | memset(ifr.ifr_addr.sa_data, 0, |
1070 | sizeof(ifr.ifr_addr.sa_data)); |
1071 | } |
1072 | |
1073 | strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); |
1074 | res = ioctl(skfd, ifra[i].s_ioctl, &ifr); |
1075 | if (res < 0) { |
1076 | int saved_errno = errno; |
1077 | |
1078 | v_print("Interface '%s': Error: SIOCS%s failed: %s\n", |
1079 | slave_ifname, ifra[i].req_name, |
1080 | strerror(saved_errno)); |
1081 | |
1082 | } |
1083 | |
1084 | ipaddr = (unsigned char *)ifr.ifr_addr.sa_data; |
1085 | v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n", |
1086 | slave_ifname, ifra[i].desc, |
1087 | ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); |
1088 | } |
1089 | |
1090 | return 0; |
1091 | } |
1092 | |
1093 | /* |
1094 | * Local variables: |
1095 | * version-control: t |
1096 | * kept-new-versions: 5 |
1097 | * c-indent-level: 4 |
1098 | * c-basic-offset: 4 |
1099 | * tab-width: 4 |
1100 | * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" |
1101 | * End: |
1102 | */ |
1103 | |
1104 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9