OpenSDE Packages Database (without history before r20070)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1125 lines
30 KiB

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