ifenslave.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106
  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, "%s", usage_msg);
  247. res = 2;
  248. goto out;
  249. }
  250. }
  251. /* options check */
  252. if (exclusive > 1) {
  253. fprintf(stderr, "%s", usage_msg);
  254. res = 2;
  255. goto out;
  256. }
  257. if (opt_v || opt_V) {
  258. printf("%s", version);
  259. if (opt_V) {
  260. res = 0;
  261. goto out;
  262. }
  263. }
  264. if (opt_u) {
  265. printf("%s", usage_msg);
  266. res = 0;
  267. goto out;
  268. }
  269. if (opt_h) {
  270. printf("%s", usage_msg);
  271. printf("%s", 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, "%s", 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, "%s", 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, "%s", 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. printf("The result of SIOCGIFMETRIC is %d\n", metric);
  497. strcpy(ifr.ifr_name, ifname);
  498. if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
  499. mtu = 0;
  500. else
  501. mtu = ifr.ifr_mtu;
  502. printf("The result of SIOCGIFMTU is %d\n", mtu);
  503. strcpy(ifr.ifr_name, ifname);
  504. if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) {
  505. memset(&dstaddr, 0, sizeof(struct sockaddr));
  506. } else
  507. dstaddr = ifr.ifr_dstaddr;
  508. strcpy(ifr.ifr_name, ifname);
  509. if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) {
  510. memset(&broadaddr, 0, sizeof(struct sockaddr));
  511. } else
  512. broadaddr = ifr.ifr_broadaddr;
  513. strcpy(ifr.ifr_name, ifname);
  514. if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) {
  515. memset(&netmask, 0, sizeof(struct sockaddr));
  516. } else
  517. netmask = ifr.ifr_netmask;
  518. return 0;
  519. }
  520. static void if_print(char *ifname)
  521. {
  522. char buff[1024];
  523. struct ifconf ifc;
  524. struct ifreq *ifr;
  525. int i;
  526. if (ifname == (char *)NULL) {
  527. ifc.ifc_len = sizeof(buff);
  528. ifc.ifc_buf = buff;
  529. if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
  530. perror("SIOCGIFCONF failed");
  531. return;
  532. }
  533. ifr = ifc.ifc_req;
  534. for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
  535. if (if_getconfig(ifr->ifr_name) < 0) {
  536. fprintf(stderr,
  537. "%s: unknown interface.\n",
  538. ifr->ifr_name);
  539. continue;
  540. }
  541. if (((mif_flags & IFF_UP) == 0) && !opt_a) continue;
  542. /*ife_print(&ife);*/
  543. }
  544. } else {
  545. if (if_getconfig(ifname) < 0) {
  546. fprintf(stderr,
  547. "%s: unknown interface.\n", ifname);
  548. }
  549. }
  550. }
  551. static int get_drv_info(char *master_ifname)
  552. {
  553. struct ifreq ifr;
  554. struct ethtool_drvinfo info;
  555. char *endptr;
  556. memset(&ifr, 0, sizeof(ifr));
  557. strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
  558. ifr.ifr_data = (caddr_t)&info;
  559. info.cmd = ETHTOOL_GDRVINFO;
  560. strncpy(info.driver, "ifenslave", 32);
  561. snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION);
  562. if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) {
  563. if (errno == EOPNOTSUPP) {
  564. goto out;
  565. }
  566. saved_errno = errno;
  567. v_print("Master '%s': Error: get bonding info failed %s\n",
  568. master_ifname, strerror(saved_errno));
  569. return 1;
  570. }
  571. abi_ver = strtoul(info.fw_version, &endptr, 0);
  572. if (*endptr) {
  573. v_print("Master '%s': Error: got invalid string as an ABI "
  574. "version from the bonding module\n",
  575. master_ifname);
  576. return 1;
  577. }
  578. out:
  579. v_print("ABI ver is %d\n", abi_ver);
  580. return 0;
  581. }
  582. static int change_active(char *master_ifname, char *slave_ifname)
  583. {
  584. struct ifreq ifr;
  585. int res = 0;
  586. if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
  587. fprintf(stderr,
  588. "Illegal operation: The specified slave interface "
  589. "'%s' is not a slave\n",
  590. slave_ifname);
  591. return 1;
  592. }
  593. strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
  594. strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
  595. if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) &&
  596. (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) {
  597. saved_errno = errno;
  598. v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: "
  599. "%s\n",
  600. master_ifname, strerror(saved_errno));
  601. res = 1;
  602. }
  603. return res;
  604. }
  605. static int enslave(char *master_ifname, char *slave_ifname)
  606. {
  607. struct ifreq ifr;
  608. int res = 0;
  609. if (slave_flags.ifr_flags & IFF_SLAVE) {
  610. fprintf(stderr,
  611. "Illegal operation: The specified slave interface "
  612. "'%s' is already a slave\n",
  613. slave_ifname);
  614. return 1;
  615. }
  616. res = set_if_down(slave_ifname, slave_flags.ifr_flags);
  617. if (res) {
  618. fprintf(stderr,
  619. "Slave '%s': Error: bring interface down failed\n",
  620. slave_ifname);
  621. return res;
  622. }
  623. if (abi_ver < 2) {
  624. /* Older bonding versions would panic if the slave has no IP
  625. * address, so get the IP setting from the master.
  626. */
  627. set_if_addr(master_ifname, slave_ifname);
  628. } else {
  629. res = clear_if_addr(slave_ifname);
  630. if (res) {
  631. fprintf(stderr,
  632. "Slave '%s': Error: clear address failed\n",
  633. slave_ifname);
  634. return res;
  635. }
  636. }
  637. if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) {
  638. res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu);
  639. if (res) {
  640. fprintf(stderr,
  641. "Slave '%s': Error: set MTU failed\n",
  642. slave_ifname);
  643. return res;
  644. }
  645. }
  646. if (hwaddr_set) {
  647. /* Master already has an hwaddr
  648. * so set it's hwaddr to the slave
  649. */
  650. if (abi_ver < 1) {
  651. /* The driver is using an old ABI, so
  652. * the application sets the slave's
  653. * hwaddr
  654. */
  655. res = set_slave_hwaddr(slave_ifname,
  656. &(master_hwaddr.ifr_hwaddr));
  657. if (res) {
  658. fprintf(stderr,
  659. "Slave '%s': Error: set hw address "
  660. "failed\n",
  661. slave_ifname);
  662. goto undo_mtu;
  663. }
  664. /* For old ABI the application needs to bring the
  665. * slave back up
  666. */
  667. res = set_if_up(slave_ifname, slave_flags.ifr_flags);
  668. if (res) {
  669. fprintf(stderr,
  670. "Slave '%s': Error: bring interface "
  671. "down failed\n",
  672. slave_ifname);
  673. goto undo_slave_mac;
  674. }
  675. }
  676. /* The driver is using a new ABI,
  677. * so the driver takes care of setting
  678. * the slave's hwaddr and bringing
  679. * it up again
  680. */
  681. } else {
  682. /* No hwaddr for master yet, so
  683. * set the slave's hwaddr to it
  684. */
  685. if (abi_ver < 1) {
  686. /* For old ABI, the master needs to be
  687. * down before setting its hwaddr
  688. */
  689. res = set_if_down(master_ifname, master_flags.ifr_flags);
  690. if (res) {
  691. fprintf(stderr,
  692. "Master '%s': Error: bring interface "
  693. "down failed\n",
  694. master_ifname);
  695. goto undo_mtu;
  696. }
  697. }
  698. res = set_master_hwaddr(master_ifname,
  699. &(slave_hwaddr.ifr_hwaddr));
  700. if (res) {
  701. fprintf(stderr,
  702. "Master '%s': Error: set hw address "
  703. "failed\n",
  704. master_ifname);
  705. goto undo_mtu;
  706. }
  707. if (abi_ver < 1) {
  708. /* For old ABI, bring the master
  709. * back up
  710. */
  711. res = set_if_up(master_ifname, master_flags.ifr_flags);
  712. if (res) {
  713. fprintf(stderr,
  714. "Master '%s': Error: bring interface "
  715. "up failed\n",
  716. master_ifname);
  717. goto undo_master_mac;
  718. }
  719. }
  720. hwaddr_set = 1;
  721. }
  722. /* Do the real thing */
  723. strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
  724. strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
  725. if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) &&
  726. (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) {
  727. saved_errno = errno;
  728. v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n",
  729. master_ifname, strerror(saved_errno));
  730. res = 1;
  731. }
  732. if (res) {
  733. goto undo_master_mac;
  734. }
  735. return 0;
  736. /* rollback (best effort) */
  737. undo_master_mac:
  738. set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr));
  739. hwaddr_set = 0;
  740. goto undo_mtu;
  741. undo_slave_mac:
  742. set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr));
  743. undo_mtu:
  744. set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu);
  745. return res;
  746. }
  747. static int release(char *master_ifname, char *slave_ifname)
  748. {
  749. struct ifreq ifr;
  750. int res = 0;
  751. if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
  752. fprintf(stderr,
  753. "Illegal operation: The specified slave interface "
  754. "'%s' is not a slave\n",
  755. slave_ifname);
  756. return 1;
  757. }
  758. strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
  759. strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
  760. if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) &&
  761. (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) {
  762. saved_errno = errno;
  763. v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n",
  764. master_ifname, strerror(saved_errno));
  765. return 1;
  766. } else if (abi_ver < 1) {
  767. /* The driver is using an old ABI, so we'll set the interface
  768. * down to avoid any conflicts due to same MAC/IP
  769. */
  770. res = set_if_down(slave_ifname, slave_flags.ifr_flags);
  771. if (res) {
  772. fprintf(stderr,
  773. "Slave '%s': Error: bring interface "
  774. "down failed\n",
  775. slave_ifname);
  776. }
  777. }
  778. /* set to default mtu */
  779. set_slave_mtu(slave_ifname, 1500);
  780. return res;
  781. }
  782. static int get_if_settings(char *ifname, struct dev_ifr ifra[])
  783. {
  784. int i;
  785. int res = 0;
  786. for (i = 0; ifra[i].req_ifr; i++) {
  787. strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ);
  788. res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr);
  789. if (res < 0) {
  790. saved_errno = errno;
  791. v_print("Interface '%s': Error: %s failed: %s\n",
  792. ifname, ifra[i].req_name,
  793. strerror(saved_errno));
  794. return saved_errno;
  795. }
  796. }
  797. return 0;
  798. }
  799. static int get_slave_flags(char *slave_ifname)
  800. {
  801. int res = 0;
  802. strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ);
  803. res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags);
  804. if (res < 0) {
  805. saved_errno = errno;
  806. v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n",
  807. slave_ifname, strerror(saved_errno));
  808. } else {
  809. v_print("Slave %s: flags %04X.\n",
  810. slave_ifname, slave_flags.ifr_flags);
  811. }
  812. return res;
  813. }
  814. static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr)
  815. {
  816. unsigned char *addr = (unsigned char *)hwaddr->sa_data;
  817. struct ifreq ifr;
  818. int res = 0;
  819. strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
  820. memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
  821. res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
  822. if (res < 0) {
  823. saved_errno = errno;
  824. v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n",
  825. master_ifname, strerror(saved_errno));
  826. return res;
  827. } else {
  828. v_print("Master '%s': hardware address set to "
  829. "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
  830. master_ifname, addr[0], addr[1], addr[2],
  831. addr[3], addr[4], addr[5]);
  832. }
  833. return res;
  834. }
  835. static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr)
  836. {
  837. unsigned char *addr = (unsigned char *)hwaddr->sa_data;
  838. struct ifreq ifr;
  839. int res = 0;
  840. strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
  841. memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
  842. res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
  843. if (res < 0) {
  844. saved_errno = errno;
  845. v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n",
  846. slave_ifname, strerror(saved_errno));
  847. if (saved_errno == EBUSY) {
  848. v_print(" The device is busy: it must be idle "
  849. "before running this command.\n");
  850. } else if (saved_errno == EOPNOTSUPP) {
  851. v_print(" The device does not support setting "
  852. "the MAC address.\n"
  853. " Your kernel likely does not support slave "
  854. "devices.\n");
  855. } else if (saved_errno == EINVAL) {
  856. v_print(" The device's address type does not match "
  857. "the master's address type.\n");
  858. }
  859. return res;
  860. } else {
  861. v_print("Slave '%s': hardware address set to "
  862. "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
  863. slave_ifname, addr[0], addr[1], addr[2],
  864. addr[3], addr[4], addr[5]);
  865. }
  866. return res;
  867. }
  868. static int set_slave_mtu(char *slave_ifname, int mtu)
  869. {
  870. struct ifreq ifr;
  871. int res = 0;
  872. ifr.ifr_mtu = mtu;
  873. strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
  874. res = ioctl(skfd, SIOCSIFMTU, &ifr);
  875. if (res < 0) {
  876. saved_errno = errno;
  877. v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n",
  878. slave_ifname, strerror(saved_errno));
  879. } else {
  880. v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu);
  881. }
  882. return res;
  883. }
  884. static int set_if_flags(char *ifname, short flags)
  885. {
  886. struct ifreq ifr;
  887. int res = 0;
  888. ifr.ifr_flags = flags;
  889. strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  890. res = ioctl(skfd, SIOCSIFFLAGS, &ifr);
  891. if (res < 0) {
  892. saved_errno = errno;
  893. v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n",
  894. ifname, strerror(saved_errno));
  895. } else {
  896. v_print("Interface '%s': flags set to %04X.\n", ifname, flags);
  897. }
  898. return res;
  899. }
  900. static int set_if_up(char *ifname, short flags)
  901. {
  902. return set_if_flags(ifname, flags | IFF_UP);
  903. }
  904. static int set_if_down(char *ifname, short flags)
  905. {
  906. return set_if_flags(ifname, flags & ~IFF_UP);
  907. }
  908. static int clear_if_addr(char *ifname)
  909. {
  910. struct ifreq ifr;
  911. int res = 0;
  912. strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  913. ifr.ifr_addr.sa_family = AF_INET;
  914. memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data));
  915. res = ioctl(skfd, SIOCSIFADDR, &ifr);
  916. if (res < 0) {
  917. saved_errno = errno;
  918. v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n",
  919. ifname, strerror(saved_errno));
  920. } else {
  921. v_print("Interface '%s': address cleared\n", ifname);
  922. }
  923. return res;
  924. }
  925. static int set_if_addr(char *master_ifname, char *slave_ifname)
  926. {
  927. struct ifreq ifr;
  928. int res;
  929. unsigned char *ipaddr;
  930. int i;
  931. struct {
  932. char *req_name;
  933. char *desc;
  934. int g_ioctl;
  935. int s_ioctl;
  936. } ifra[] = {
  937. {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR},
  938. {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR},
  939. {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR},
  940. {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK},
  941. {NULL, NULL, 0, 0},
  942. };
  943. for (i = 0; ifra[i].req_name; i++) {
  944. strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
  945. res = ioctl(skfd, ifra[i].g_ioctl, &ifr);
  946. if (res < 0) {
  947. int saved_errno = errno;
  948. v_print("Interface '%s': Error: SIOCG%s failed: %s\n",
  949. master_ifname, ifra[i].req_name,
  950. strerror(saved_errno));
  951. ifr.ifr_addr.sa_family = AF_INET;
  952. memset(ifr.ifr_addr.sa_data, 0,
  953. sizeof(ifr.ifr_addr.sa_data));
  954. }
  955. strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
  956. res = ioctl(skfd, ifra[i].s_ioctl, &ifr);
  957. if (res < 0) {
  958. int saved_errno = errno;
  959. v_print("Interface '%s': Error: SIOCS%s failed: %s\n",
  960. slave_ifname, ifra[i].req_name,
  961. strerror(saved_errno));
  962. }
  963. ipaddr = (unsigned char *)ifr.ifr_addr.sa_data;
  964. v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n",
  965. slave_ifname, ifra[i].desc,
  966. ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
  967. }
  968. return 0;
  969. }
  970. /*
  971. * Local variables:
  972. * version-control: t
  973. * kept-new-versions: 5
  974. * c-indent-level: 4
  975. * c-basic-offset: 4
  976. * tab-width: 4
  977. * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave"
  978. * End:
  979. */