Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ifenslave.c
Go to the documentation of this file.
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 <[email protected]>
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 [email protected], 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 ([email protected]).\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 */
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, "%s", usage_msg);
264  res = 2;
265  goto out;
266  }
267  }
268 
269  /* options check */
270  if (exclusive > 1) {
271  fprintf(stderr, "%s", usage_msg);
272  res = 2;
273  goto out;
274  }
275 
276  if (opt_v || opt_V) {
277  printf("%s", version);
278  if (opt_V) {
279  res = 0;
280  goto out;
281  }
282  }
283 
284  if (opt_u) {
285  printf("%s", usage_msg);
286  res = 0;
287  goto out;
288  }
289 
290  if (opt_h) {
291  printf("%s", usage_msg);
292  printf("%s", 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, "%s", 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, "%s", 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, "%s", 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  printf("The result of SIOCGIFMETRIC is %d\n", metric);
543 
544  strcpy(ifr.ifr_name, ifname);
545  if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
546  mtu = 0;
547  else
548  mtu = ifr.ifr_mtu;
549  printf("The result of SIOCGIFMTU is %d\n", mtu);
550 
551  strcpy(ifr.ifr_name, ifname);
552  if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) {
553  memset(&dstaddr, 0, sizeof(struct sockaddr));
554  } else
555  dstaddr = ifr.ifr_dstaddr;
556 
557  strcpy(ifr.ifr_name, ifname);
558  if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) {
559  memset(&broadaddr, 0, sizeof(struct sockaddr));
560  } else
561  broadaddr = ifr.ifr_broadaddr;
562 
563  strcpy(ifr.ifr_name, ifname);
564  if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) {
565  memset(&netmask, 0, sizeof(struct sockaddr));
566  } else
567  netmask = ifr.ifr_netmask;
568 
569  return 0;
570 }
571 
572 static void if_print(char *ifname)
573 {
574  char buff[1024];
575  struct ifconf ifc;
576  struct ifreq *ifr;
577  int i;
578 
579  if (ifname == (char *)NULL) {
580  ifc.ifc_len = sizeof(buff);
581  ifc.ifc_buf = buff;
582  if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
583  perror("SIOCGIFCONF failed");
584  return;
585  }
586 
587  ifr = ifc.ifc_req;
588  for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
589  if (if_getconfig(ifr->ifr_name) < 0) {
590  fprintf(stderr,
591  "%s: unknown interface.\n",
592  ifr->ifr_name);
593  continue;
594  }
595 
596  if (((mif_flags & IFF_UP) == 0) && !opt_a) continue;
597  /*ife_print(&ife);*/
598  }
599  } else {
600  if (if_getconfig(ifname) < 0) {
601  fprintf(stderr,
602  "%s: unknown interface.\n", ifname);
603  }
604  }
605 }
606 
607 static int get_drv_info(char *master_ifname)
608 {
609  struct ifreq ifr;
610  struct ethtool_drvinfo info;
611  char *endptr;
612 
613  memset(&ifr, 0, sizeof(ifr));
614  strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
615  ifr.ifr_data = (caddr_t)&info;
616 
617  info.cmd = ETHTOOL_GDRVINFO;
618  strncpy(info.driver, "ifenslave", 32);
619  snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION);
620 
621  if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) {
622  if (errno == EOPNOTSUPP) {
623  goto out;
624  }
625 
626  saved_errno = errno;
627  v_print("Master '%s': Error: get bonding info failed %s\n",
628  master_ifname, strerror(saved_errno));
629  return 1;
630  }
631 
632  abi_ver = strtoul(info.fw_version, &endptr, 0);
633  if (*endptr) {
634  v_print("Master '%s': Error: got invalid string as an ABI "
635  "version from the bonding module\n",
636  master_ifname);
637  return 1;
638  }
639 
640 out:
641  v_print("ABI ver is %d\n", abi_ver);
642 
643  return 0;
644 }
645 
646 static int change_active(char *master_ifname, char *slave_ifname)
647 {
648  struct ifreq ifr;
649  int res = 0;
650 
651  if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
652  fprintf(stderr,
653  "Illegal operation: The specified slave interface "
654  "'%s' is not a slave\n",
655  slave_ifname);
656  return 1;
657  }
658 
659  strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
660  strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
661  if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) &&
662  (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) {
663  saved_errno = errno;
664  v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: "
665  "%s\n",
666  master_ifname, strerror(saved_errno));
667  res = 1;
668  }
669 
670  return res;
671 }
672 
673 static int enslave(char *master_ifname, char *slave_ifname)
674 {
675  struct ifreq ifr;
676  int res = 0;
677 
678  if (slave_flags.ifr_flags & IFF_SLAVE) {
679  fprintf(stderr,
680  "Illegal operation: The specified slave interface "
681  "'%s' is already a slave\n",
682  slave_ifname);
683  return 1;
684  }
685 
686  res = set_if_down(slave_ifname, slave_flags.ifr_flags);
687  if (res) {
688  fprintf(stderr,
689  "Slave '%s': Error: bring interface down failed\n",
690  slave_ifname);
691  return res;
692  }
693 
694  if (abi_ver < 2) {
695  /* Older bonding versions would panic if the slave has no IP
696  * address, so get the IP setting from the master.
697  */
698  set_if_addr(master_ifname, slave_ifname);
699  } else {
700  res = clear_if_addr(slave_ifname);
701  if (res) {
702  fprintf(stderr,
703  "Slave '%s': Error: clear address failed\n",
704  slave_ifname);
705  return res;
706  }
707  }
708 
709  if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) {
710  res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu);
711  if (res) {
712  fprintf(stderr,
713  "Slave '%s': Error: set MTU failed\n",
714  slave_ifname);
715  return res;
716  }
717  }
718 
719  if (hwaddr_set) {
720  /* Master already has an hwaddr
721  * so set it's hwaddr to the slave
722  */
723  if (abi_ver < 1) {
724  /* The driver is using an old ABI, so
725  * the application sets the slave's
726  * hwaddr
727  */
728  res = set_slave_hwaddr(slave_ifname,
729  &(master_hwaddr.ifr_hwaddr));
730  if (res) {
731  fprintf(stderr,
732  "Slave '%s': Error: set hw address "
733  "failed\n",
734  slave_ifname);
735  goto undo_mtu;
736  }
737 
738  /* For old ABI the application needs to bring the
739  * slave back up
740  */
741  res = set_if_up(slave_ifname, slave_flags.ifr_flags);
742  if (res) {
743  fprintf(stderr,
744  "Slave '%s': Error: bring interface "
745  "down failed\n",
746  slave_ifname);
747  goto undo_slave_mac;
748  }
749  }
750  /* The driver is using a new ABI,
751  * so the driver takes care of setting
752  * the slave's hwaddr and bringing
753  * it up again
754  */
755  } else {
756  /* No hwaddr for master yet, so
757  * set the slave's hwaddr to it
758  */
759  if (abi_ver < 1) {
760  /* For old ABI, the master needs to be
761  * down before setting its hwaddr
762  */
763  res = set_if_down(master_ifname, master_flags.ifr_flags);
764  if (res) {
765  fprintf(stderr,
766  "Master '%s': Error: bring interface "
767  "down failed\n",
768  master_ifname);
769  goto undo_mtu;
770  }
771  }
772 
773  res = set_master_hwaddr(master_ifname,
774  &(slave_hwaddr.ifr_hwaddr));
775  if (res) {
776  fprintf(stderr,
777  "Master '%s': Error: set hw address "
778  "failed\n",
779  master_ifname);
780  goto undo_mtu;
781  }
782 
783  if (abi_ver < 1) {
784  /* For old ABI, bring the master
785  * back up
786  */
787  res = set_if_up(master_ifname, master_flags.ifr_flags);
788  if (res) {
789  fprintf(stderr,
790  "Master '%s': Error: bring interface "
791  "up failed\n",
792  master_ifname);
793  goto undo_master_mac;
794  }
795  }
796 
797  hwaddr_set = 1;
798  }
799 
800  /* Do the real thing */
801  strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
802  strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
803  if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) &&
804  (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) {
805  saved_errno = errno;
806  v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n",
807  master_ifname, strerror(saved_errno));
808  res = 1;
809  }
810 
811  if (res) {
812  goto undo_master_mac;
813  }
814 
815  return 0;
816 
817 /* rollback (best effort) */
818 undo_master_mac:
819  set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr));
820  hwaddr_set = 0;
821  goto undo_mtu;
822 undo_slave_mac:
823  set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr));
824 undo_mtu:
825  set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu);
826  return res;
827 }
828 
829 static int release(char *master_ifname, char *slave_ifname)
830 {
831  struct ifreq ifr;
832  int res = 0;
833 
834  if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
835  fprintf(stderr,
836  "Illegal operation: The specified slave interface "
837  "'%s' is not a slave\n",
838  slave_ifname);
839  return 1;
840  }
841 
842  strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
843  strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
844  if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) &&
845  (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) {
846  saved_errno = errno;
847  v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n",
848  master_ifname, strerror(saved_errno));
849  return 1;
850  } else if (abi_ver < 1) {
851  /* The driver is using an old ABI, so we'll set the interface
852  * down to avoid any conflicts due to same MAC/IP
853  */
854  res = set_if_down(slave_ifname, slave_flags.ifr_flags);
855  if (res) {
856  fprintf(stderr,
857  "Slave '%s': Error: bring interface "
858  "down failed\n",
859  slave_ifname);
860  }
861  }
862 
863  /* set to default mtu */
864  set_slave_mtu(slave_ifname, 1500);
865 
866  return res;
867 }
868 
869 static int get_if_settings(char *ifname, struct dev_ifr ifra[])
870 {
871  int i;
872  int res = 0;
873 
874  for (i = 0; ifra[i].req_ifr; i++) {
875  strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ);
876  res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr);
877  if (res < 0) {
878  saved_errno = errno;
879  v_print("Interface '%s': Error: %s failed: %s\n",
880  ifname, ifra[i].req_name,
882 
883  return saved_errno;
884  }
885  }
886 
887  return 0;
888 }
889 
890 static int get_slave_flags(char *slave_ifname)
891 {
892  int res = 0;
893 
894  strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ);
895  res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags);
896  if (res < 0) {
897  saved_errno = errno;
898  v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n",
899  slave_ifname, strerror(saved_errno));
900  } else {
901  v_print("Slave %s: flags %04X.\n",
902  slave_ifname, slave_flags.ifr_flags);
903  }
904 
905  return res;
906 }
907 
908 static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr)
909 {
910  unsigned char *addr = (unsigned char *)hwaddr->sa_data;
911  struct ifreq ifr;
912  int res = 0;
913 
914  strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
915  memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
916  res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
917  if (res < 0) {
918  saved_errno = errno;
919  v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n",
920  master_ifname, strerror(saved_errno));
921  return res;
922  } else {
923  v_print("Master '%s': hardware address set to "
924  "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
925  master_ifname, addr[0], addr[1], addr[2],
926  addr[3], addr[4], addr[5]);
927  }
928 
929  return res;
930 }
931 
932 static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr)
933 {
934  unsigned char *addr = (unsigned char *)hwaddr->sa_data;
935  struct ifreq ifr;
936  int res = 0;
937 
938  strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
939  memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
940  res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
941  if (res < 0) {
942  saved_errno = errno;
943 
944  v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n",
945  slave_ifname, strerror(saved_errno));
946 
947  if (saved_errno == EBUSY) {
948  v_print(" The device is busy: it must be idle "
949  "before running this command.\n");
950  } else if (saved_errno == EOPNOTSUPP) {
951  v_print(" The device does not support setting "
952  "the MAC address.\n"
953  " Your kernel likely does not support slave "
954  "devices.\n");
955  } else if (saved_errno == EINVAL) {
956  v_print(" The device's address type does not match "
957  "the master's address type.\n");
958  }
959  return res;
960  } else {
961  v_print("Slave '%s': hardware address set to "
962  "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
963  slave_ifname, addr[0], addr[1], addr[2],
964  addr[3], addr[4], addr[5]);
965  }
966 
967  return res;
968 }
969 
970 static int set_slave_mtu(char *slave_ifname, int mtu)
971 {
972  struct ifreq ifr;
973  int res = 0;
974 
975  ifr.ifr_mtu = mtu;
976  strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
977 
978  res = ioctl(skfd, SIOCSIFMTU, &ifr);
979  if (res < 0) {
980  saved_errno = errno;
981  v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n",
982  slave_ifname, strerror(saved_errno));
983  } else {
984  v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu);
985  }
986 
987  return res;
988 }
989 
990 static int set_if_flags(char *ifname, short flags)
991 {
992  struct ifreq ifr;
993  int res = 0;
994 
995  ifr.ifr_flags = flags;
996  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
997 
998  res = ioctl(skfd, SIOCSIFFLAGS, &ifr);
999  if (res < 0) {
1000  saved_errno = errno;
1001  v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n",
1002  ifname, strerror(saved_errno));
1003  } else {
1004  v_print("Interface '%s': flags set to %04X.\n", ifname, flags);
1005  }
1006 
1007  return res;
1008 }
1009 
1010 static int set_if_up(char *ifname, short flags)
1011 {
1012  return set_if_flags(ifname, flags | IFF_UP);
1013 }
1014 
1015 static int set_if_down(char *ifname, short flags)
1016 {
1017  return set_if_flags(ifname, flags & ~IFF_UP);
1018 }
1019 
1020 static int clear_if_addr(char *ifname)
1021 {
1022  struct ifreq ifr;
1023  int res = 0;
1024 
1025  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
1026  ifr.ifr_addr.sa_family = AF_INET;
1027  memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data));
1028 
1029  res = ioctl(skfd, SIOCSIFADDR, &ifr);
1030  if (res < 0) {
1031  saved_errno = errno;
1032  v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n",
1033  ifname, strerror(saved_errno));
1034  } else {
1035  v_print("Interface '%s': address cleared\n", ifname);
1036  }
1037 
1038  return res;
1039 }
1040 
1041 static int set_if_addr(char *master_ifname, char *slave_ifname)
1042 {
1043  struct ifreq ifr;
1044  int res;
1045  unsigned char *ipaddr;
1046  int i;
1047  struct {
1048  char *req_name;
1049  char *desc;
1050  int g_ioctl;
1051  int s_ioctl;
1052  } ifra[] = {
1053  {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR},
1054  {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR},
1055  {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR},
1056  {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK},
1057  {NULL, NULL, 0, 0},
1058  };
1059 
1060  for (i = 0; ifra[i].req_name; i++) {
1061  strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
1062  res = ioctl(skfd, ifra[i].g_ioctl, &ifr);
1063  if (res < 0) {
1064  int saved_errno = errno;
1065 
1066  v_print("Interface '%s': Error: SIOCG%s failed: %s\n",
1067  master_ifname, ifra[i].req_name,
1068  strerror(saved_errno));
1069 
1070  ifr.ifr_addr.sa_family = AF_INET;
1071  memset(ifr.ifr_addr.sa_data, 0,
1072  sizeof(ifr.ifr_addr.sa_data));
1073  }
1074 
1075  strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
1076  res = ioctl(skfd, ifra[i].s_ioctl, &ifr);
1077  if (res < 0) {
1078  int saved_errno = errno;
1079 
1080  v_print("Interface '%s': Error: SIOCS%s failed: %s\n",
1081  slave_ifname, ifra[i].req_name,
1082  strerror(saved_errno));
1083 
1084  }
1085 
1086  ipaddr = (unsigned char *)ifr.ifr_addr.sa_data;
1087  v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n",
1088  slave_ifname, ifra[i].desc,
1089  ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
1090  }
1091 
1092  return 0;
1093 }
1094 
1095 /*
1096  * Local variables:
1097  * version-control: t
1098  * kept-new-versions: 5
1099  * c-indent-level: 4
1100  * c-basic-offset: 4
1101  * tab-width: 4
1102  * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave"
1103  * End:
1104  */
1105