Commit f307b1c9 authored by Shmulik Hen's avatar Shmulik Hen Committed by Jeff Garzik

[PATCH] bonding cleanup 2.6 - Simplify ifenslave

ifenslave lite - No more IP settings to slaves, unified printing
format, code re-org and broken to more functions.
parent 4576b4fa
...@@ -973,13 +973,12 @@ Donald Becker's Ethernet Drivers and diag programs may be found at : ...@@ -973,13 +973,12 @@ Donald Becker's Ethernet Drivers and diag programs may be found at :
You will also find a lot of information regarding Ethernet, NWay, MII, etc. at You will also find a lot of information regarding Ethernet, NWay, MII, etc. at
www.scyld.com. www.scyld.com.
For new versions of the driver, patches for older kernels and the updated Patches for 2.2 kernels are at Willy Tarreau's site :
userspace tools, take a look at Willy Tarreau's site :
- http://wtarreau.free.fr/pub/bonding/ - http://wtarreau.free.fr/pub/bonding/
- http://www-miaif.lip6.fr/willy/pub/bonding/ - http://www-miaif.lip6.fr/~tarreau/pub/bonding/
To get latest informations about Linux Kernel development, please consult To get latest informations about Linux Kernel development, please consult
the Linux Kernel Mailing List Archives at : the Linux Kernel Mailing List Archives at :
http://boudicca.tux.org/hypermail/linux-kernel/latest/ http://www.ussg.iu.edu/hypermail/linux/kernel/
-- END -- -- END --
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
* This program controls the Linux implementation of running multiple * This program controls the Linux implementation of running multiple
* network interfaces in parallel. * network interfaces in parallel.
* *
* Usage: ifenslave [-v] master-interface < slave-interface [metric <N>] > ...
*
* Author: Donald Becker <becker@cesdis.gsfc.nasa.gov> * Author: Donald Becker <becker@cesdis.gsfc.nasa.gov>
* Copyright 1994-1996 Donald Becker * Copyright 1994-1996 Donald Becker
* *
...@@ -90,24 +88,30 @@ ...@@ -90,24 +88,30 @@
* - For opt_c: slave should not be set to the master's setting * - For opt_c: slave should not be set to the master's setting
* while it is running. It was already set during enslave. To * while it is running. It was already set during enslave. To
* simplify things, it is now handeled separately. * simplify things, it is now handeled separately.
*
* - 2003/09/24 - Shmulik Hen <shmulik.hen at intel dot com>
* - Code cleanup and style changes
* set version to 1.1.0
*/ */
#define APP_VERSION "1.0.12" #define APP_VERSION "1.1.0"
#define APP_RELDATE "June 30, 2003" #define APP_RELDATE "Septemer 24, 2003"
#define APP_NAME "ifenslave" #define APP_NAME "ifenslave"
static char *version = static char *version =
APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ") " "\nDonald Becker (becker@cesdis.gsfc.nasa.gov).\n" APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ")\n"
"detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" "o Donald Becker (becker@cesdis.gsfc.nasa.gov).\n"
"2.4 kernel support added on 2001/02/16 by Chad N. Tindel (ctindel at ieee dot org.\n"; "o Detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n"
"o 2.4 kernel support added on 2001/02/16 by Chad N. Tindel\n"
" (ctindel at ieee dot org).\n";
static const char *usage_msg = static const char *usage_msg =
"Usage: ifenslave [-adfrvVh] <master-interface> < <slave-if> [metric <N>] > ...\n" "Usage: ifenslave [-f] <master-if> <slave-if> [<slave-if>...]\n"
" ifenslave -c master-interface slave-if\n"; " ifenslave -d <master-if> <slave-if> [<slave-if>...]\n"
" ifenslave -c <master-if> <slave-if>\n"
" ifenslave --help\n";
static const char *howto_msg = static const char *help_msg =
"Usage: ifenslave [-adfrvVh] <master-interface> < <slave-if> [metric <N>] > ...\n"
" ifenslave -c master-interface slave-if\n"
"\n" "\n"
" To create a bond device, simply follow these three steps :\n" " To create a bond device, simply follow these three steps :\n"
" - ensure that the required drivers are properly loaded :\n" " - ensure that the required drivers are properly loaded :\n"
...@@ -115,18 +119,32 @@ static const char *howto_msg = ...@@ -115,18 +119,32 @@ static const char *howto_msg =
" - assign an IP address to the bond device :\n" " - assign an IP address to the bond device :\n"
" # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\n" " # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\n"
" - attach all the interfaces you need to the bond device :\n" " - attach all the interfaces you need to the bond device :\n"
" # ifenslave bond0 eth0 eth1 eth2\n" " # ifenslave [{-f|--force}] bond0 eth0 [eth1 [eth2]...]\n"
" If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n"
" interfaces attached AFTER this assignment will get the same MAC addr.\n" " interfaces attached AFTER this assignment will get the same MAC addr.\n"
"\n" " (except for ALB/TLB modes)\n"
" To detach a dead interface without setting the bond device down :\n"
" # ifenslave -d bond0 eth1\n"
"\n" "\n"
" To set the bond device down and automatically release all the slaves :\n" " To set the bond device down and automatically release all the slaves :\n"
" # ifconfig bond0 down\n" " # ifconfig bond0 down\n"
"\n" "\n"
" To detach a dead interface without setting the bond device down :\n"
" # ifenslave {-d|--detach} bond0 eth0 [eth1 [eth2]...]\n"
"\n"
" To change active slave :\n" " To change active slave :\n"
" # ifenslave -c bond0 eth0\n" " # ifenslave {-c|--change-active} bond0 eth0\n"
"\n"
" To show master interface info\n"
" # ifenslave bond0\n"
"\n"
" To show all interfaces info\n"
" # ifenslave {-a|--all-interfaces}\n"
"\n"
" To be more verbose\n"
" # ifenslave {-v|--verbose} ...\n"
"\n"
" # ifenslave {-u|--usage} Show usage\n"
" # ifenslave {-V|--version} Show version\n"
" # ifenslave {-h|--help} This message\n"
"\n"; "\n";
#include <unistd.h> #include <unistd.h>
...@@ -155,474 +173,330 @@ typedef __uint8_t u8; /* ditto */ ...@@ -155,474 +173,330 @@ typedef __uint8_t u8; /* ditto */
struct option longopts[] = { struct option longopts[] = {
/* { name has_arg *flag val } */ /* { name has_arg *flag val } */
{"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */
{"change-active", 0, 0, 'c'}, /* Change the active slave. */
{"detach", 0, 0, 'd'}, /* Detach a slave interface. */
{"force", 0, 0, 'f'}, /* Force the operation. */ {"force", 0, 0, 'f'}, /* Force the operation. */
{"help", 0, 0, '?'}, /* Give help */ {"help", 0, 0, 'h'}, /* Give help */
{"howto", 0, 0, 'h'}, /* Give some more help */ {"usage", 0, 0, 'u'}, /* Give usage */
{"receive-slave", 0, 0, 'r'}, /* Make a receive-only slave. */
{"verbose", 0, 0, 'v'}, /* Report each action taken. */ {"verbose", 0, 0, 'v'}, /* Report each action taken. */
{"version", 0, 0, 'V'}, /* Emit version information. */ {"version", 0, 0, 'V'}, /* Emit version information. */
{"detach", 0, 0, 'd'}, /* Detach a slave interface. */ { 0, 0, 0, 0}
{"change-active", 0, 0, 'c'}, /* Change the active slave. */
{ 0, 0, 0, 0 }
}; };
/* Command-line flags. */ /* Command-line flags. */
unsigned int unsigned int
opt_a = 0, /* Show-all-interfaces flag. */ opt_a = 0, /* Show-all-interfaces flag. */
opt_c = 0, /* Change-active-slave flag. */
opt_d = 0, /* Detach a slave interface. */
opt_f = 0, /* Force the operation. */ opt_f = 0, /* Force the operation. */
opt_r = 0, /* Set up a Rx-only slave. */ opt_h = 0, /* Help */
opt_d = 0, /* detach a slave interface. */ opt_u = 0, /* Usage */
opt_c = 0, /* change-active-slave flag. */ opt_v = 0, /* Verbose flag. */
verbose = 0, /* Verbose flag. */ opt_V = 0; /* Version */
opt_version = 0,
opt_howto = 0; int skfd = -1; /* AF_INET socket for ioctl() calls.*/
int skfd = -1; /* AF_INET socket for ioctl() calls. */ int abi_ver = 0; /* userland - kernel ABI version */
int hwaddr_set = 0; /* Master's hwaddr is set */
int saved_errno;
struct ifreq master_mtu, master_flags, master_hwaddr;
struct ifreq slave_mtu, slave_flags, slave_hwaddr;
struct dev_ifr {
struct ifreq *req_ifr;
char *req_name;
int req_type;
};
static void if_print(char *ifname); struct dev_ifr master_ifra[] = {
static int get_abi_ver(char *master_ifname); {&master_mtu, "SIOCGIFMTU", SIOCGIFMTU},
{&master_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS},
{&master_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR},
{NULL, "", 0}
};
int struct dev_ifr slave_ifra[] = {
main(int argc, char **argv) {&slave_mtu, "SIOCGIFMTU", SIOCGIFMTU},
{&slave_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS},
{&slave_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR},
{NULL, "", 0}
};
static void if_print(char *ifname);
static int get_drv_info(char *master_ifname);
static int get_if_settings(char *ifname, struct dev_ifr ifra[]);
static int get_slave_flags(char *slave_ifname);
static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr);
static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr);
static int set_slave_mtu(char *slave_ifname, int mtu);
static int set_if_flags(char *ifname, short flags);
static int set_if_up(char *ifname, short flags);
static int set_if_down(char *ifname, short flags);
static int clear_if_addr(char *ifname);
static int set_if_addr(char *master_ifname, char *slave_ifname);
static int change_active(char *master_ifname, char *slave_ifname);
static int enslave(char *master_ifname, char *slave_ifname);
static int release(char *master_ifname, char *slave_ifname);
#define v_print(fmt, args...) \
if (opt_v) \
fprintf(stderr, fmt, ## args )
int main(int argc, char *argv[])
{ {
struct ifreq ifr2, if_hwaddr, if_ipaddr, if_metric, if_mtu, if_dstaddr;
struct ifreq if_netmask, if_brdaddr, if_flags;
int rv, goterr = 0;
int c, errflag = 0;
sa_family_t master_family;
char **spp, *master_ifname, *slave_ifname; char **spp, *master_ifname, *slave_ifname;
int hwaddr_notset; int c, i, rv;
int abi_ver = 0; int res = 0;
int exclusive = 0;
while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF) while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) {
switch (c) { switch (c) {
case 'a': opt_a++; break; case 'a': opt_a++; exclusive++; break;
case 'f': opt_f++; break; case 'c': opt_c++; exclusive++; break;
case 'r': opt_r++; break; case 'd': opt_d++; exclusive++; break;
case 'd': opt_d++; break; case 'f': opt_f++; exclusive++; break;
case 'c': opt_c++; break; case 'h': opt_h++; exclusive++; break;
case 'v': verbose++; break; case 'u': opt_u++; exclusive++; break;
case 'V': opt_version++; break; case 'v': opt_v++; break;
case 'h': opt_howto++; break; case 'V': opt_V++; exclusive++; break;
case '?': errflag++;
} case '?':
/* option check */
if (opt_c)
if(opt_a || opt_f || opt_r || opt_d || verbose || opt_version ||
opt_howto || errflag ) {
fprintf(stderr, usage_msg); fprintf(stderr, usage_msg);
return 2; res = 2;
goto out;
}
} }
if (errflag) { /* options check */
if (exclusive > 1) {
fprintf(stderr, usage_msg); fprintf(stderr, usage_msg);
return 2; res = 2;
goto out;
} }
if (opt_howto) { if (opt_v || opt_V) {
fprintf(stderr, howto_msg); printf(version);
return 0; if (opt_V) {
res = 0;
goto out;
}
} }
if (verbose || opt_version) { if (opt_u) {
printf(version); printf(usage_msg);
if (opt_version) res = 0;
exit(0); goto out;
} }
/* Open a basic socket. */ if (opt_h) {
if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) { printf(usage_msg);
perror("socket"); printf(help_msg);
exit(-1); res = 0;
goto out;
} }
if (verbose) /* Open a basic socket */
fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n", if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
argc, optind, argv[optind]); perror("socket");
res = 1;
goto out;
}
/* No remaining args means show all interfaces. */ if (opt_a) {
if (optind == argc) { if (optind == argc) {
/* No remaining args */
/* show all interfaces */
if_print((char *)NULL); if_print((char *)NULL);
(void) close(skfd); goto out;
exit(0); } else {
/* Just show usage */
fprintf(stderr, usage_msg);
res = 2;
goto out;
}
} }
/* Copy the interface name. */ /* Copy the interface name */
spp = argv + optind; spp = argv + optind;
master_ifname = *spp++; master_ifname = *spp++;
slave_ifname = *spp++;
/* Check command line. */ if (master_ifname == NULL) {
if (opt_c) {
char **tempp = spp;
if ((master_ifname == NULL)||(slave_ifname == NULL)||(*tempp++ != NULL)) {
fprintf(stderr, usage_msg); fprintf(stderr, usage_msg);
(void) close(skfd); res = 2;
return 2; goto out;
} }
}
/* A single args means show the configuration for this interface. */
if (slave_ifname == NULL) {
if_print(master_ifname);
(void) close(skfd);
exit(0);
}
/* exchange abi version with bonding driver */
abi_ver = get_abi_ver(master_ifname);
if (abi_ver < 0) {
(void) close(skfd);
exit(1);
}
/* Get the vitals from the master interface. */
{
struct ifreq *ifra[7] = { &if_ipaddr, &if_mtu, &if_dstaddr,
&if_brdaddr, &if_netmask, &if_flags,
&if_hwaddr };
const char *req_name[7] = {
"IP address", "MTU", "destination address",
"broadcast address", "netmask", "status flags",
"hardware address" };
const int ioctl_req_type[7] = {
SIOCGIFADDR, SIOCGIFMTU, SIOCGIFDSTADDR,
SIOCGIFBRDADDR, SIOCGIFNETMASK, SIOCGIFFLAGS,
SIOCGIFHWADDR };
int i;
for (i = 0; i < 7; i++) { /* exchange abi version with bonding module */
strncpy(ifra[i]->ifr_name, master_ifname, IFNAMSIZ); res = get_drv_info(master_ifname);
if (ioctl(skfd, ioctl_req_type[i], ifra[i]) < 0) { if (res) {
fprintf(stderr, fprintf(stderr,
"Something broke getting the master's %s: %s.\n", "Master '%s': Error: handshake with driver failed. "
req_name[i], strerror(errno)); "Aborting\n",
}
}
/* check if master is up; if not then fail any operation */
if (!(if_flags.ifr_flags & IFF_UP)) {
fprintf(stderr, "Illegal operation; the specified master interface '%s' is not up.\n", master_ifname);
(void) close(skfd);
exit (1);
}
hwaddr_notset = 1; /* assume master's address not set yet */
for (i = 0; hwaddr_notset && (i < 6); i++) {
hwaddr_notset &= ((unsigned char *)if_hwaddr.ifr_hwaddr.sa_data)[i] == 0;
}
/* The family '1' is ARPHRD_ETHER for ethernet. */
if (if_hwaddr.ifr_hwaddr.sa_family != 1 && !opt_f) {
fprintf(stderr, "The specified master interface '%s' is not"
" ethernet-like.\n This program is designed to work"
" with ethernet-like network interfaces.\n"
" Use the '-f' option to force the operation.\n",
master_ifname); master_ifname);
(void) close(skfd); goto out;
exit (1);
}
master_family = if_hwaddr.ifr_hwaddr.sa_family;
if (verbose) {
unsigned char *hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
printf("The current hardware address (SIOCGIFHWADDR) of %s is type %d "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", master_ifname,
if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
}
} }
slave_ifname = *spp++;
/* do this when enslaving interfaces */ if (slave_ifname == NULL) {
do { if (opt_d || opt_c) {
if (opt_d) { /* detach a slave interface from the master */ fprintf(stderr, usage_msg);
strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); res = 2;
strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); goto out;
if ((ioctl(skfd, SIOCBONDRELEASE, &if_flags) < 0) &&
(ioctl(skfd, BOND_RELEASE_OLD, &if_flags) < 0)) {
fprintf(stderr, "SIOCBONDRELEASE: cannot detach %s from %s. errno=%s.\n",
slave_ifname, master_ifname, strerror(errno));
}
else if (abi_ver < 1) {
/* The driver is using an old ABI, so we'll set the interface
* down to avoid any conflicts due to same IP/MAC
*/
strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ);
if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) {
int saved_errno = errno;
fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname,
strerror(saved_errno));
}
else {
ifr2.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) {
int saved_errno = errno;
fprintf(stderr, "Shutting down interface %s failed: %s\n",
slave_ifname, strerror(saved_errno));
}
}
}
} else if (opt_c) { /* change primary slave */
strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ);
strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ);
if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) &&
(ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) {
fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno));
} }
} else { /* attach a slave interface to the master */
strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); /* A single arg means show the
if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { * configuration for this interface
int saved_errno = errno; */
fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, if_print(master_ifname);
strerror(saved_errno)); goto out;
(void) close(skfd);
return 1;
} }
if ((ifr2.ifr_flags & IFF_SLAVE) && !opt_r) { res = get_if_settings(master_ifname, master_ifra);
fprintf(stderr, "%s is already a slave\n", slave_ifname); if (res) {
(void) close(skfd); /* Probably a good reason not to go on */
return 1; fprintf(stderr,
"Master '%s': Error: get settings failed: %s. "
"Aborting\n",
master_ifname, strerror(res));
goto out;
} }
/* if hwaddr_notset, assign the slave hw address to the master */ /* check if master is indeed a master;
if (hwaddr_notset) { * if not then fail any operation
/* assign the slave hw address to the
* master since it currently does not
* have one; otherwise, slaves may
* have different hw addresses in
* active-backup mode as seen when enslaving
* using "ifenslave bond0 eth0 eth1" because
* hwaddr_notset is set outside this loop.
* TODO: put this and the "else" portion in
* a function.
*/ */
/* get the slaves MAC address */ if (!(master_flags.ifr_flags & IFF_MASTER)) {
strncpy(if_hwaddr.ifr_name, slave_ifname,
IFNAMSIZ);
rv = ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr);
if (-1 == rv) {
fprintf(stderr, "Could not get MAC "
"address of %s: %s\n",
slave_ifname,
strerror(errno));
strncpy(if_hwaddr.ifr_name,
master_ifname, IFNAMSIZ);
goterr = 1;
}
if (!goterr) {
if (abi_ver < 1) {
/* In ABI versions older than 1, the
* master's set_mac routine couldn't
* work if it was up, because it
* used the default ethernet set_mac
* function.
*/
/* bring master down */
if_flags.ifr_flags &= ~IFF_UP;
if (ioctl(skfd, SIOCSIFFLAGS,
&if_flags) < 0) {
goterr = 1;
fprintf(stderr, fprintf(stderr,
"Shutting down " "Illegal operation; the specified interface '%s' "
"interface %s failed: " "is not a master. Aborting\n",
"%s\n", master_ifname);
master_ifname, res = 1;
strerror(errno)); goto out;
}
} }
strncpy(if_hwaddr.ifr_name, /* check if master is up; if not then fail any operation */
master_ifname, IFNAMSIZ); if (!(master_flags.ifr_flags & IFF_UP)) {
if (ioctl(skfd, SIOCSIFHWADDR,
&if_hwaddr) < 0) {
fprintf(stderr, fprintf(stderr,
"Could not set MAC " "Illegal operation; the specified master interface "
"address of %s: %s\n", "'%s' is not up.\n",
master_ifname, master_ifname);
strerror(errno)); res = 1;
goterr=1; goto out;
} else {
hwaddr_notset = 0;
} }
if (abi_ver < 1) { /* Only for enslaving */
/* bring master back up */ if (!opt_c && !opt_d) {
if_flags.ifr_flags |= IFF_UP; sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family;
if (ioctl(skfd, SIOCSIFFLAGS, unsigned char *hwaddr =
&if_flags) < 0) { (unsigned char *)master_hwaddr.ifr_hwaddr.sa_data;
fprintf(stderr,
"Bringing up interface "
"%s failed: %s\n",
master_ifname,
strerror(errno));
}
}
}
} else if (abi_ver < 1) { /* if (hwaddr_notset) */
/* The driver is using an old ABI, so we'll set the interface /* The family '1' is ARPHRD_ETHER for ethernet. */
* down and assign the master's hwaddr to it if (master_family != 1 && !opt_f) {
*/ fprintf(stderr,
if (ifr2.ifr_flags & IFF_UP) { "Illegal operation: The specified master "
ifr2.ifr_flags &= ~IFF_UP; "interface '%s' is not ethernet-like.\n "
if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { "This program is designed to work with "
int saved_errno = errno; "ethernet-like network interfaces.\n "
fprintf(stderr, "Shutting down interface %s failed: %s\n", "Use the '-f' option to force the "
slave_ifname, strerror(saved_errno)); "operation.\n",
} master_ifname);
res = 1;
goto out;
} }
strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ); /* Check master's hw addr */
if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { for (i = 0; i < 6; i++) {
int saved_errno = errno; if (hwaddr[i] != 0) {
fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name, hwaddr_set = 1;
strerror(saved_errno)); break;
if (saved_errno == EBUSY)
fprintf(stderr, " The slave device %s is busy: it must be"
" idle before running this command.\n", slave_ifname);
else if (saved_errno == EOPNOTSUPP)
fprintf(stderr, " The slave device you specified does not support"
" setting the MAC address.\n Your kernel likely does not"
" support slave devices.\n");
else if (saved_errno == EINVAL)
fprintf(stderr, " The slave device's address type does not match"
" the master's address type.\n");
} else {
if (verbose) {
unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data;
printf("Slave's (%s) hardware address set to "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", slave_ifname,
hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
}
} }
} }
if (*spp && !strcmp(*spp, "metric")) { if (hwaddr_set) {
if (*++spp == NULL) { v_print("current hardware address of master '%s' "
fprintf(stderr, usage_msg); "is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
(void) close(skfd); "type %d\n",
exit(2); master_ifname,
} hwaddr[0], hwaddr[1],
if_metric.ifr_metric = atoi(*spp); hwaddr[2], hwaddr[3],
strncpy(if_metric.ifr_name, slave_ifname, IFNAMSIZ); hwaddr[4], hwaddr[5],
if (ioctl(skfd, SIOCSIFMETRIC, &if_metric) < 0) { master_family);
fprintf(stderr, "SIOCSIFMETRIC on %s: %s\n", slave_ifname,
strerror(errno));
goterr = 1;
} }
spp++;
} }
if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 /* Accepts only one slave */
|| ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) { if (opt_c) {
/* change active slave */
res = get_slave_flags(slave_ifname);
if (res) {
fprintf(stderr, fprintf(stderr,
"Something broke setting the slave's address: %s.\n", "Slave '%s': Error: get flags failed. "
strerror(errno)); "Aborting\n",
} else { slave_ifname);
if (verbose) { goto out;
unsigned char *ipaddr = if_ipaddr.ifr_addr.sa_data;
printf("Set the slave's (%s) IP address to %d.%d.%d.%d.\n",
slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
} }
res = change_active(master_ifname, slave_ifname);
if (res) {
fprintf(stderr,
"Master '%s', Slave '%s': Error: "
"Change active failed\n",
master_ifname, slave_ifname);
} }
if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0
|| ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) {
fprintf(stderr, "Something broke setting the slave MTU: %s.\n",
strerror(errno));
} else { } else {
if (verbose) /* Accept multiple slaves */
printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu); do {
} if (opt_d) {
/* detach a slave interface from the master */
if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 rv = get_slave_flags(slave_ifname);
|| ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) { if (rv) {
fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n", /* Can't work with this slave. */
slave_ifname, strerror(errno)); /* remember the error and skip it*/
} else {
if (verbose) {
unsigned char *ipaddr = if_dstaddr.ifr_dstaddr.sa_data;
printf("Set the slave's (%s) destination address to %d.%d.%d.%d.\n",
slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
}
}
if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0
|| ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) {
fprintf(stderr, fprintf(stderr,
"Something broke setting the slave (%s) broadcast address: %s.\n", "Slave '%s': Error: get flags "
slave_ifname, strerror(errno)); "failed. Skipping\n",
} else { slave_ifname);
if (verbose) { res = rv;
unsigned char *ipaddr = if_brdaddr.ifr_broadaddr.sa_data; continue;
printf("Set the slave's (%s) broadcast address to %d.%d.%d.%d.\n",
slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
}
} }
rv = release(master_ifname, slave_ifname);
if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0 if (rv) {
|| ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) {
fprintf(stderr, fprintf(stderr,
"Something broke setting the slave (%s) netmask: %s.\n", "Master '%s', Slave '%s': Error: "
slave_ifname, strerror(errno)); "Release failed\n",
} else { master_ifname, slave_ifname);
if (verbose) { res = rv;
unsigned char *ipaddr = if_netmask.ifr_netmask.sa_data;
printf("Set the slave's (%s) netmask to %d.%d.%d.%d.\n",
slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
}
} }
if (abi_ver < 1) {
/* The driver is using an old ABI, so we'll set the interface
* up before enslaving it
*/
ifr2.ifr_flags |= IFF_UP;
if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0
|| strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0
|| ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) {
fprintf(stderr,
"Something broke setting the slave (%s) flags: %s.\n",
slave_ifname, strerror(errno));
} else { } else {
if (verbose) /* attach a slave interface to the master */
printf("Set the slave's (%s) flags %4.4x.\n", rv = get_if_settings(slave_ifname, slave_ifra);
slave_ifname, if_flags.ifr_flags); if (rv) {
/* Can't work with this slave. */
/* remember the error and skip it*/
fprintf(stderr,
"Slave '%s': Error: get "
"settings failed: %s. "
"Skipping\n",
slave_ifname, strerror(rv));
res = rv;
continue;
} }
} else { rv = enslave(master_ifname, slave_ifname);
/* the bonding module takes care of setting the slave's mac address if (rv) {
* and opening its interface fprintf(stderr,
*/ "Master '%s', Slave '%s': Error: "
if (ifr2.ifr_flags & IFF_UP) { /* the interface will need to be down */ "Enslave failed\n",
ifr2.ifr_flags &= ~IFF_UP; master_ifname, slave_ifname);
if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { res = rv;
int saved_errno = errno;
fprintf(stderr, "Shutting down interface %s failed: %s\n",
slave_ifname, strerror(saved_errno));
} }
} }
} while ((slave_ifname = *spp++) != NULL);
} }
/* Do the real thing */ out:
if (!opt_r) { if (skfd >= 0) {
strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); close(skfd);
strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ);
if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) &&
(ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) {
fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno));
}
}
} }
} while ( (slave_ifname = *spp++) != NULL);
/* Close the socket. */ return res;
(void) close(skfd);
return(goterr);
} }
static short mif_flags; static short mif_flags;
...@@ -633,6 +507,7 @@ static int if_getconfig(char *ifname) ...@@ -633,6 +507,7 @@ static int if_getconfig(char *ifname)
struct ifreq ifr; struct ifreq ifr;
int metric, mtu; /* Parameters of the master interface. */ int metric, mtu; /* Parameters of the master interface. */
struct sockaddr dstaddr, broadaddr, netmask; struct sockaddr dstaddr, broadaddr, netmask;
unsigned char *hwaddr;
strcpy(ifr.ifr_name, ifname); strcpy(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
...@@ -652,14 +527,12 @@ static int if_getconfig(char *ifname) ...@@ -652,14 +527,12 @@ static int if_getconfig(char *ifname)
if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
return -1; return -1;
{
/* Gotta convert from 'char' to unsigned for printf(). */ /* Gotta convert from 'char' to unsigned for printf(). */
unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data;
printf("The result of SIOCGIFHWADDR is type %d " printf("The result of SIOCGIFHWADDR is type %d "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
}
strcpy(ifr.ifr_name, ifname); strcpy(ifr.ifr_name, ifname);
if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) {
...@@ -691,7 +564,7 @@ static int if_getconfig(char *ifname) ...@@ -691,7 +564,7 @@ static int if_getconfig(char *ifname)
} else } else
netmask = ifr.ifr_netmask; netmask = ifr.ifr_netmask;
return(0); return 0;
} }
static void if_print(char *ifname) static void if_print(char *ifname)
...@@ -705,14 +578,15 @@ static void if_print(char *ifname) ...@@ -705,14 +578,15 @@ static void if_print(char *ifname)
ifc.ifc_len = sizeof(buff); ifc.ifc_len = sizeof(buff);
ifc.ifc_buf = buff; ifc.ifc_buf = buff;
if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); perror("SIOCGIFCONF failed");
return; return;
} }
ifr = ifc.ifc_req; ifr = ifc.ifc_req;
for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
if (if_getconfig(ifr->ifr_name) < 0) { if (if_getconfig(ifr->ifr_name) < 0) {
fprintf(stderr, "%s: unknown interface.\n", fprintf(stderr,
"%s: unknown interface.\n",
ifr->ifr_name); ifr->ifr_name);
continue; continue;
} }
...@@ -721,16 +595,18 @@ static void if_print(char *ifname) ...@@ -721,16 +595,18 @@ static void if_print(char *ifname)
/*ife_print(&ife);*/ /*ife_print(&ife);*/
} }
} else { } else {
if (if_getconfig(ifname) < 0) if (if_getconfig(ifname) < 0) {
fprintf(stderr, "%s: unknown interface.\n", ifname); fprintf(stderr,
"%s: unknown interface.\n", ifname);
}
} }
} }
static int get_abi_ver(char *master_ifname) static int get_drv_info(char *master_ifname)
{ {
struct ifreq ifr; struct ifreq ifr;
struct ethtool_drvinfo info; struct ethtool_drvinfo info;
int abi_ver = 0; char *endptr;
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
...@@ -739,24 +615,487 @@ static int get_abi_ver(char *master_ifname) ...@@ -739,24 +615,487 @@ static int get_abi_ver(char *master_ifname)
info.cmd = ETHTOOL_GDRVINFO; info.cmd = ETHTOOL_GDRVINFO;
strncpy(info.driver, "ifenslave", 32); strncpy(info.driver, "ifenslave", 32);
snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION);
if (ioctl(skfd, SIOCETHTOOL, &ifr) >= 0) {
char *endptr; if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) {
if (errno == EOPNOTSUPP) {
goto out;
}
saved_errno = errno;
v_print("Master '%s': Error: get bonding info failed %s\n",
master_ifname, strerror(saved_errno));
return 1;
}
abi_ver = strtoul(info.fw_version, &endptr, 0); abi_ver = strtoul(info.fw_version, &endptr, 0);
if (*endptr) { if (*endptr) {
fprintf(stderr, "Error: got invalid string as an ABI " v_print("Master '%s': Error: got invalid string as an ABI "
"version from the bonding module\n"); "version from the bonding module\n",
return -1; master_ifname);
return 1;
}
out:
v_print("ABI ver is %d\n", abi_ver);
return 0;
}
static int change_active(char *master_ifname, char *slave_ifname)
{
struct ifreq ifr;
int res = 0;
if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
fprintf(stderr,
"Illegal operation: The specified slave interface "
"'%s' is not a slave\n",
slave_ifname);
return 1;
}
strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) &&
(ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) {
saved_errno = errno;
v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: "
"%s\n",
master_ifname, strerror(saved_errno));
res = 1;
}
return res;
}
static int enslave(char *master_ifname, char *slave_ifname)
{
struct ifreq ifr;
int res = 0;
if (slave_flags.ifr_flags & IFF_SLAVE) {
fprintf(stderr,
"Illegal operation: The specified slave interface "
"'%s' is already a slave\n",
slave_ifname);
return 1;
}
res = set_if_down(slave_ifname, slave_flags.ifr_flags);
if (res) {
fprintf(stderr,
"Slave '%s': Error: bring interface down failed\n",
slave_ifname);
return res;
}
if (abi_ver < 2) {
/* Older bonding versions would panic if the slave has no IP
* address, so get the IP setting from the master.
*/
res = set_if_addr(master_ifname, slave_ifname);
if (res) {
fprintf(stderr,
"Slave '%s': Error: set address failed\n",
slave_ifname);
return res;
}
} else {
res = clear_if_addr(slave_ifname);
if (res) {
fprintf(stderr,
"Slave '%s': Error: clear address failed\n",
slave_ifname);
return res;
}
}
if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) {
res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu);
if (res) {
fprintf(stderr,
"Slave '%s': Error: set MTU failed\n",
slave_ifname);
return res;
}
}
if (hwaddr_set) {
/* Master already has an hwaddr
* so set it's hwaddr to the slave
*/
if (abi_ver < 1) {
/* The driver is using an old ABI, so
* the application sets the slave's
* hwaddr
*/
res = set_slave_hwaddr(slave_ifname,
&(master_hwaddr.ifr_hwaddr));
if (res) {
fprintf(stderr,
"Slave '%s': Error: set hw address "
"failed\n",
slave_ifname);
goto undo_mtu;
}
/* For old ABI the application needs to bring the
* slave back up
*/
res = set_if_up(slave_ifname, slave_flags.ifr_flags);
if (res) {
fprintf(stderr,
"Slave '%s': Error: bring interface "
"down failed\n",
slave_ifname);
goto undo_slave_mac;
}
}
/* The driver is using a new ABI,
* so the driver takes care of setting
* the slave's hwaddr and bringing
* it up again
*/
} else {
/* No hwaddr for master yet, so
* set the slave's hwaddr to it
*/
if (abi_ver < 1) {
/* For old ABI, the master needs to be
* down before setting it's hwaddr
*/
res = set_if_down(master_ifname, master_flags.ifr_flags);
if (res) {
fprintf(stderr,
"Master '%s': Error: bring interface "
"down failed\n",
master_ifname);
goto undo_mtu;
}
}
res = set_master_hwaddr(master_ifname,
&(slave_hwaddr.ifr_hwaddr));
if (res) {
fprintf(stderr,
"Master '%s': Error: set hw address "
"failed\n",
master_ifname);
goto undo_mtu;
}
if (abi_ver < 1) {
/* For old ABI, bring the master
* back up
*/
res = set_if_up(master_ifname, master_flags.ifr_flags);
if (res) {
fprintf(stderr,
"Master '%s': Error: bring interface "
"up failed\n",
master_ifname);
goto undo_master_mac;
}
}
hwaddr_set = 1;
}
/* Do the real thing */
strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) &&
(ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) {
saved_errno = errno;
v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n",
master_ifname, strerror(saved_errno));
res = 1;
}
if (res) {
goto undo_master_mac;
}
return 0;
/* rollback (best effort) */
undo_master_mac:
set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr));
hwaddr_set = 0;
goto undo_mtu;
undo_slave_mac:
set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr));
undo_mtu:
set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu);
return res;
}
static int release(char *master_ifname, char *slave_ifname)
{
struct ifreq ifr;
int res = 0;
if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
fprintf(stderr,
"Illegal operation: The specified slave interface "
"'%s' is not a slave\n",
slave_ifname);
return 1;
}
strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) &&
(ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) {
saved_errno = errno;
v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n",
master_ifname, strerror(saved_errno));
return 1;
} else if (abi_ver < 1) {
/* The driver is using an old ABI, so we'll set the interface
* down to avoid any conflicts due to same MAC/IP
*/
res = set_if_down(slave_ifname, slave_flags.ifr_flags);
if (res) {
fprintf(stderr,
"Slave '%s': Error: bring interface "
"down failed\n",
slave_ifname);
}
}
/* set to default mtu */
set_slave_mtu(slave_ifname, 1500);
return res;
}
static int get_if_settings(char *ifname, struct dev_ifr ifra[])
{
int i;
int res = 0;
for (i = 0; ifra[i].req_ifr; i++) {
strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ);
res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr);
if (res < 0) {
saved_errno = errno;
v_print("Interface '%s': Error: %s failed: %s\n",
ifname, ifra[i].req_name,
strerror(saved_errno));
return saved_errno;
} }
} }
if (verbose) { return 0;
printf("ABI ver is %d\n", abi_ver); }
static int get_slave_flags(char *slave_ifname)
{
int res = 0;
strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ);
res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags);
if (res < 0) {
saved_errno = errno;
v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n",
slave_ifname, strerror(saved_errno));
} else {
v_print("Slave %s: flags %04X.\n",
slave_ifname, slave_flags.ifr_flags);
}
return res;
}
static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr)
{
unsigned char *addr = (unsigned char *)hwaddr->sa_data;
struct ifreq ifr;
int res = 0;
strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
if (res < 0) {
saved_errno = errno;
v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n",
master_ifname, strerror(saved_errno));
return res;
} else {
v_print("Master '%s': hardware address set to "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
master_ifname, addr[0], addr[1], addr[2],
addr[3], addr[4], addr[5]);
} }
return abi_ver;
return res;
} }
static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr)
{
unsigned char *addr = (unsigned char *)hwaddr->sa_data;
struct ifreq ifr;
int res = 0;
strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
if (res < 0) {
saved_errno = errno;
v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n",
slave_ifname, strerror(saved_errno));
if (saved_errno == EBUSY) {
v_print(" The device is busy: it must be idle "
"before running this command.\n");
} else if (saved_errno == EOPNOTSUPP) {
v_print(" The device does not support setting "
"the MAC address.\n"
" Your kernel likely does not support slave "
"devices.\n");
} else if (saved_errno == EINVAL) {
v_print(" The device's address type does not match "
"the master's address type.\n");
}
return res;
} else {
v_print("Slave '%s': hardware address set to "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
slave_ifname, addr[0], addr[1], addr[2],
addr[3], addr[4], addr[5]);
}
return res;
}
static int set_slave_mtu(char *slave_ifname, int mtu)
{
struct ifreq ifr;
int res = 0;
ifr.ifr_mtu = mtu;
strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
res = ioctl(skfd, SIOCSIFMTU, &ifr);
if (res < 0) {
saved_errno = errno;
v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n",
slave_ifname, strerror(saved_errno));
} else {
v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu);
}
return res;
}
static int set_if_flags(char *ifname, short flags)
{
struct ifreq ifr;
int res = 0;
ifr.ifr_flags = flags;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
res = ioctl(skfd, SIOCSIFFLAGS, &ifr);
if (res < 0) {
saved_errno = errno;
v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n",
ifname, strerror(saved_errno));
} else {
v_print("Interface '%s': flags set to %04X.\n", ifname, flags);
}
return res;
}
static int set_if_up(char *ifname, short flags)
{
return set_if_flags(ifname, flags | IFF_UP);
}
static int set_if_down(char *ifname, short flags)
{
return set_if_flags(ifname, flags & ~IFF_UP);
}
static int clear_if_addr(char *ifname)
{
struct ifreq ifr;
int res = 0;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data));
res = ioctl(skfd, SIOCSIFADDR, &ifr);
if (res < 0) {
saved_errno = errno;
v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n",
ifname, strerror(saved_errno));
} else {
v_print("Interface '%s': address cleared\n", ifname);
}
return res;
}
static int set_if_addr(char *master_ifname, char *slave_ifname)
{
struct ifreq ifr;
int res;
unsigned char *ipaddr;
int i;
struct {
char *req_name;
char *desc;
int g_ioctl;
int s_ioctl;
} ifra[] = {
{"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR},
{"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR},
{"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR},
{"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK},
{NULL, NULL, 0, 0},
};
for (i = 0; ifra[i].req_name; i++) {
strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
res = ioctl(skfd, ifra[i].g_ioctl, &ifr);
if (res < 0) {
int saved_errno = errno;
v_print("Interface '%s': Error: SIOCG%s failed: %s\n",
master_ifname, ifra[i].req_name,
strerror(saved_errno));
ifr.ifr_addr.sa_family = AF_INET;
memset(ifr.ifr_addr.sa_data, 0,
sizeof(ifr.ifr_addr.sa_data));
}
strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
res = ioctl(skfd, ifra[i].s_ioctl, &ifr);
if (res < 0) {
int saved_errno = errno;
v_print("Interface '%s': Error: SIOCS%s failed: %s\n",
slave_ifname, ifra[i].req_name,
strerror(saved_errno));
return res;
}
ipaddr = ifr.ifr_addr.sa_data;
v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n",
slave_ifname, ifra[i].desc,
ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
}
return 0;
}
/* /*
* Local variables: * Local variables:
...@@ -768,3 +1107,4 @@ static int get_abi_ver(char *master_ifname) ...@@ -768,3 +1107,4 @@ static int get_abi_ver(char *master_ifname)
* compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave"
* End: * End:
*/ */
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
/* userland - kernel ABI version (2003/05/08) */ /* userland - kernel ABI version (2003/05/08) */
#define BOND_ABI_VERSION 1 #define BOND_ABI_VERSION 2
/* /*
* We can remove these ioctl definitions in 2.5. People should use the * We can remove these ioctl definitions in 2.5. People should use the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment