ifenslave.c 29 KB

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