Bonding on 2.4.3, ifenslave wierdness

Daniel Pfenniger daniel.pfenniger at obs.unige.ch
Sun Apr 29 23:10:56 PDT 2001


Aaron Van Couwenberghe wrote:
> 
> On Fri, Apr 27, 2001 at 07:37:57AM +0200, daniel.pfenniger at obs.unige.ch wrote:
> > With 2.4 kernels ifenslave is no longer required.  There is a bug
> > up to kernel 2.4.2 at bonding stop (typically at shutdown)
> > crashing the kernel.
> >
> > My configuration files are (RedHat 6.2, kernel 2.4.3, tulip cards):
> 
> Thank you for the reply.
> 
> How would one duplicate this configuration on a non-redhat box? Is ifenslave
> now replaced by command line options to ifconfig? If so, what version of
> ifconfig do I need?
> 
> Are you sure you don't have ifenslave on your system? sysconfig could be
> calling it for you...

Sorry what I said is wrong.  After verification (locate ifenslave) 
I did keep ifenslave in /sbin from older kernels.  ifenslave is 
necessary for bonding properly.

In recent kernels the bonding.txt documentation has been removed 
from the kernel Documentation/networking directory.  Probably its
information was too inacurate and nobody found time the write an 
up-to-date version. 

I found two different (diff -b) versions of ifenslave.c circulating 
on the Net with the same version number: 
"ifenslave.c:v0.07 9/9/97  Donald Becker
(becker at cesdis.gsfc.nasa.gov)\n"; 

The version working with the 2.4.3 kernel is joined here as attachment, 
as distinctive line it has among many others
#include <linux/if_bonding.h> 

I hope this helps. 

	Dan
-------------- next part --------------
/* Mode: C;
 * ifenslave.c: Configure network interfaces for parallel routing.
 *
 *	This program controls the Linux implementation of running multiple
 *	network interfaces in parallel.
 *
 * Usage:	ifenslave [-v] master-interface slave-interface [metric <N>]
 *
 * Author:	Donald Becker <becker at cesdis.gsfc.nasa.gov>
 *		Copyright 1994-1996 Donald Becker
 *
 *		This program is free software; you can redistribute it
 *		and/or modify it under the terms of the GNU General Public
 *		License as published by the Free Software Foundation.
 *
 *	The author may be reached as becker at CESDIS.gsfc.nasa.gov, or C/O
 *	Center of Excellence in Space Data and Information Sciences
 *	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 */

static char *version =
"ifenslave.c:v0.07 9/9/97  Donald Becker (becker at cesdis.gsfc.nasa.gov)\n";
static const char *usage_msg =
"Usage: ifenslave [-afrvV] <master-interface> <slave-interface> [metric <N>]\n";

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/types.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_bonding.h>

struct option longopts[] = {
 /* { name  has_arg  *flag  val } */
    {"all-interfaces", 0, 0, 'a'},	/* Show all interfaces. */
    {"force",       0, 0, 'f'},		/* Force the operation. */
    {"help", 		0, 0, '?'},		/* Give help */
    {"receive-slave", 0, 0, 'r'},	/* Make a receive-only slave.  */
    {"verbose", 	0, 0, 'v'},		/* Report each action taken.  */
    {"version", 	0, 0, 'V'},		/* Emit version information.  */
    { 0, 0, 0, 0 }
};

/* Command-line flags. */
unsigned int
opt_a = 0,					/* Show-all-interfaces flag. */
opt_f = 0,					/* Force the operation. */
opt_r = 0,					/* Set up a Rx-only slave. */
verbose = 0,					/* Verbose flag. */
opt_version;
int skfd = -1;					/* AF_INET socket for ioctl() calls.	*/

static void if_print(char *ifname);

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 goterr = 0;
	int c, errflag = 0;
	char **spp, *master_ifname, *slave_ifname;

	while ((c = getopt_long(argc, argv, "afrvV?", longopts, 0)) != EOF)
		switch (c) {
		case 'a': opt_a++; break;
		case 'f': opt_f++; break;
		case 'r': opt_r++; break;
		case 'v': verbose++;		break;
		case 'V': opt_version++;	break;
		case '?': errflag++;
		}
	if (errflag) {
		fprintf(stderr, usage_msg);
		return 2;
	}

	if (verbose || opt_version)
		printf(version);

	/* Open a basic socket. */
	if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) {
		perror("socket");
		exit(-1);
	}

#ifdef notdef
	/* Find options scattered throughout the command line.
	   I should change this to use getopt() sometime. */
	argc--; argv++;
	while (*argv[0] == '-') {
		char *argp = *argv++;
		argc--;
		while (*++argp) {
			switch (*argp) {
			default:
				fprintf(stderr, "Unrecognized option '%c'.\n%s",
						argp[0], usage_msg);
				return 2;
			}
		}
	}
#endif

	if (verbose)
		fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n",
				argc, optind, argv[optind]);

	/* No remaining args means show all interfaces. */
	if (optind == argc) {
		if_print((char *)NULL);
		(void) close(skfd);
		exit(0);
	}

	/* Copy the interface name. */
	spp = argv + optind;
	master_ifname = *spp++;
	slave_ifname = *spp++;

	/* A single args means show the configuration for this interface. */
	if (slave_ifname == NULL) {
		if_print(master_ifname);
		(void) close(skfd);
		exit(0);
	}

	/* Get the vitals from the master interface. */
	strncpy(if_hwaddr.ifr_name, master_ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr) < 0) {
		fprintf(stderr, "SIOCGIFHWADDR on %s failed: %s\n", master_ifname,
				strerror(errno));
		return 1;
	} else {		/* Gotta convert from 'char' to unsigned for printf().  */
		unsigned char *hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;

		/* 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);

			return 1;
		}

		{ 
			int i, cnt=0;
			for (i=0; i<6; i++) {
				if (hwaddr[i] == 0)
					cnt++;
			}
			if (cnt == 6) {
				printf("master has no hw address assigned; getting one from slave!\n");
				strncpy(ifr2.ifr_name, master_ifname, IFNAMSIZ);
				strncpy(ifr2.ifr_slave, slave_ifname, IFNAMSIZ);
				if (ioctl(skfd, BOND_SETHWADDR, &ifr2) < 0) {
					fprintf(stderr, 
							"BOND_SETHWADDR on %s failed: %s\n", slave_ifname,
							strerror(errno));
					return 1;
				}
				strncpy(if_hwaddr.ifr_name, master_ifname, IFNAMSIZ);
				if (ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr) < 0) {
					fprintf(stderr, "SIOCGIFHWADDR on %s failed: %s\n", 
							master_ifname, strerror(errno));
					return 1;
				}
			}
		}

		if (verbose)
			printf("The 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]);
	}

	{
		struct ifreq *ifra[6] = { &if_ipaddr, &if_mtu, &if_dstaddr,
									 &if_brdaddr, &if_netmask, &if_flags };
		const char *req_name[6] = {
			"IP address", "MTU", "destination address",
			"broadcast address", "netmask", "status flags", };
		const int ioctl_req_type[6] = {
			SIOCGIFADDR, SIOCGIFMTU, SIOCGIFDSTADDR,
			SIOCGIFBRDADDR, SIOCGIFNETMASK, SIOCGIFFLAGS, };
		int i;

		for (i = 0; i < 6; i++) {
			strncpy(ifra[i]->ifr_name, master_ifname, IFNAMSIZ);
			if (ioctl(skfd, ioctl_req_type[i], ifra[i]) < 0) {
				fprintf(stderr,
						"Something broke getting the master's %s: %s.\n",
						req_name[i], strerror(errno));
			}
		}
	}

	do {
		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));
			return 1;
		}
		if (ifr2.ifr_flags & IFF_UP) {
			printf("The interface %s is up, shutting it down it to enslave it.\n",
				   slave_ifname);
			ifr2.ifr_flags &= ~IFF_UP;
			if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) {
				int saved_errno = errno;
				fprintf(stderr, "Shutting down interface %s failed: %s\n",
						slave_ifname, strerror(saved_errno));
			}
		}

		strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ);
		if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) {
			int saved_errno = errno;
			fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name,
					strerror(saved_errno));
			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");
			return 1;
		} else {
			if (verbose) {
				unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data;
				printf("Set the slave's hardware address to "
					   "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", hwaddr[0],
					   hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
			}
		}
		
		if (*spp  &&  !strcmp(*spp, "metric")) {
			if (*++spp == NULL) {
				fprintf(stderr, usage_msg);
				exit(2);
			}
			if_metric.ifr_metric = atoi(*spp);
			if (ioctl(skfd, SIOCSIFMETRIC, &if_metric) < 0) {
				fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
				goterr = 1;
			}
			spp++;
		}

		if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0
			|| ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) {
			fprintf(stderr,
					"Something broke setting the slave's address: %s.\n",
					strerror(errno));
		} else {
			if (verbose) {
				unsigned char *ipaddr = if_ipaddr.ifr_addr.sa_data;
				printf("Set the slave's IP address to %d.%d.%d.%d.\n",
					   ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
			}
		}

		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 {
			if (verbose)
				printf("Set the slave's MTU to %d.\n", if_mtu.ifr_mtu);
		}

		if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0
			|| ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) {
			fprintf(stderr, "Error setting the slave with SIOCSIFDSTADDR: %s.\n",
					strerror(errno));
		} else {
			if (verbose) {
				unsigned char *ipaddr = if_dstaddr.ifr_dstaddr.sa_data;
				printf("Set the slave's destination address to %d.%d.%d.%d.\n",
					   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,
					"Something broke setting the slave broadcast address: %s.\n",
					strerror(errno));
		} else {
			if (verbose) {
				unsigned char *ipaddr = if_brdaddr.ifr_broadaddr.sa_data;
				printf("Set the slave's broadcast address to %d.%d.%d.%d.\n",
					   ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
			}
		}
		
		if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0
			|| ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) {
			fprintf(stderr,
					"Something broke setting the slave netmask: %s.\n",
					strerror(errno));
		} else {
			if (verbose) {
				unsigned char *ipaddr = if_netmask.ifr_netmask.sa_data;
				printf("Set the slave's netmask to %d.%d.%d.%d.\n",
					   ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
			}
		}
		
		if ((if_flags.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0
			|| strncpy(if_flags.ifr_name, slave_ifname, IFNAMSIZ) <= 0
			|| ioctl(skfd, SIOCSIFFLAGS, &if_flags) < 0) {
			fprintf(stderr,
					"Something broke setting the slave flags: %s.\n",
					strerror(errno));
		} else {
			if (verbose)
				printf("Set the slave's flags %4.4x.\n", if_flags.ifr_flags);
		}

		/* Do the real thing: set the second interface as a slave. */
		if ( ! opt_r) {
			strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ);
			strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ);
			if (ioctl(skfd, BOND_ENSLAVE, &if_flags) < 0) {
				fprintf(stderr,	"SIOCSIFSLAVE: %d (%s).\n", errno, strerror(errno));
			}
		}
	} while ( (slave_ifname = *spp++) != NULL);

	/* Close the socket. */
	(void) close(skfd);

	return(goterr);
}

static short mif_flags;

/* Get the inteface configuration from the kernel. */
static int if_getconfig(char *ifname)
{
	struct ifreq ifr;
	int metric, mtu;			/* Parameters of the master interface. */
	struct sockaddr dstaddr, broadaddr, netmask;

	strcpy(ifr.ifr_name, ifname);
	if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
		return -1;
	mif_flags = ifr.ifr_flags;
	printf("The result of SIOCGIFFLAGS on %s is %x.\n",
		   ifname, ifr.ifr_flags);

	strcpy(ifr.ifr_name, ifname);
	if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0)
		return -1;
	printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n",
		   ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1],
		   ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]);

	strcpy(ifr.ifr_name, ifname);
	if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
		return -1;

	{		/* Gotta convert from 'char' to unsigned for printf().  */
		unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data;
		printf("The result of SIOCGIFHWADDR is type %d  "
			   "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
			   ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
			   hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
	}

	strcpy(ifr.ifr_name, ifname);
	if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) {
		metric = 0;
	} else
		metric = ifr.ifr_metric;

	strcpy(ifr.ifr_name, ifname);
	if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
		mtu = 0;
	else
		mtu = ifr.ifr_mtu;

	strcpy(ifr.ifr_name, ifname);
	if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) {
		memset(&dstaddr, 0, sizeof(struct sockaddr));
	} else
		dstaddr = ifr.ifr_dstaddr;

	strcpy(ifr.ifr_name, ifname);
	if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) {
		memset(&broadaddr, 0, sizeof(struct sockaddr));
	} else
		broadaddr = ifr.ifr_broadaddr;

	strcpy(ifr.ifr_name, ifname);
	if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) {
		memset(&netmask, 0, sizeof(struct sockaddr));
	} else
		netmask = ifr.ifr_netmask;

	return(0);
}

static void if_print(char *ifname)
{
	char buff[1024];
	struct ifconf ifc;
	struct ifreq *ifr;
	int i;

	if (ifname == (char *)NULL) {
		ifc.ifc_len = sizeof(buff);
		ifc.ifc_buf = buff;
		if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
			fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
			return;
		}

		ifr = ifc.ifc_req;
		for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
			if (if_getconfig(ifr->ifr_name) < 0) {
				fprintf(stderr, "%s: unknown interface.\n",
						ifr->ifr_name);
				continue;
			}

			if (((mif_flags & IFF_UP) == 0) && !opt_a) continue;
			/*ife_print(&ife);*/
		}
	} else {
		if (if_getconfig(ifname) < 0)
			fprintf(stderr, "%s: unknown interface.\n", ifname);
	}
}


/*
 * Local variables:
 *  version-control: t
 *  kept-new-versions: 5
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 *  compile-command: "gcc -Wall -Wstrict-prototypes -O ifenslave.c -o ifenslave"
 * End:
 */


More information about the Beowulf mailing list