Subject: [PATCH 5/10] [bonding 2.6] Add support for changing HW address and MTU

From: Amir Noam <[email-masked]>
Date: Thu, 11 Sep 2003 17:40:58 +0300

diff -Nuarp a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
--- a/drivers/net/bonding/bond_main.c	Thu Sep 11 16:48:26 2003
+++ b/drivers/net/bonding/bond_main.c	Thu Sep 11 16:48:27 2003
@@ -592,6 +592,11 @@ static struct slave *find_best_interface

 /* #define BONDING_DEBUG 1 */
+#ifdef BONDING_DEBUG
+#define dprintk(x...) printk(x...)
+#else /* BONDING_DEBUG */
+#define dprintk(x...) do {} while (0)
+#endif /* BONDING_DEBUG */
 
 /* several macros */
 
@@ -3021,10 +3026,6 @@ static int bond_ioctl(struct net_device 
 		case SIOCBONDRELEASE:	
 			ret = bond_release(master_dev, slave_dev); 
 			break;
-		case BOND_SETHWADDR_OLD:
-		case SIOCBONDSETHWADDR:	
-			ret = bond_sethwaddr(master_dev, slave_dev);
-			break;
 		case BOND_CHANGE_ACTIVE_OLD:
 		case SIOCBONDCHANGEACTIVE:
 			if (USES_PRIMARY(bond_mode)) {
@@ -3464,6 +3465,132 @@ static int bond_read_proc(char *buf, cha
 }
 #endif /* CONFIG_PROC_FS */
 
+
+/*
+ * Change HW address
+ *
+ * Note that many devices must be down to change the HW address, and
+ * downing the master releases all slaves.  We can make bonds full of
+ * bonding devices to test this, however.
+ */
+static inline int
+bond_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct bonding *bond = dev->priv;
+	struct sockaddr *sa = addr, tmp_sa;
+	struct slave *slave;
+	int error;
+
+	dprintk(KERN_INFO "bond_set_mac_address %p %s\n", dev,
+	       dev->name);
+
+	if (!is_valid_ether_addr(sa->sa_data)) {
+		return -EADDRNOTAVAIL;
+	}
+
+	for (slave = bond->prev; slave != (struct slave *)bond;
+	     slave = slave->prev) {
+		dprintk(KERN_INFO "bond_set_mac: slave %p %s\n", slave,
+			slave->dev->name);
+		if (slave->dev->set_mac_address == NULL) {
+			error = -EOPNOTSUPP;
+			dprintk(KERN_INFO "bond_set_mac EOPNOTSUPP %s\n",
+				slave->dev->name);
+			goto unwind;
+		}
+
+		error = slave->dev->set_mac_address(slave->dev, addr);
+		if (error) {
+			/* TODO: consider downing the slave 
+			 * and retry ?
+			 * User should expect communications
+			 * breakage anyway until ARP finish
+			 * updating, so...
+			 */
+			dprintk(KERN_INFO "bond_set_mac err %d %s\n",
+				error, slave->dev->name);
+			goto unwind;
+		}
+	}
+
+	/* success */
+	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+	return 0;
+
+unwind:
+	memcpy(tmp_sa.sa_data, dev->dev_addr, dev->addr_len);
+	tmp_sa.sa_family = dev->type;
+
+	for (slave = slave->next; slave != bond->next;
+	     slave = slave->next) {
+		int tmp_error;
+
+		tmp_error = slave->dev->set_mac_address(slave->dev, &tmp_sa);
+		if (tmp_error) {
+			dprintk(KERN_INFO "bond_set_mac_address: "
+				"unwind err %d dev %s\n",
+				tmp_error, slave->dev->name);
+		}
+	}
+
+	return error;
+}
+
+/*
+ * Change the MTU of all of a master's slaves to match the master
+ */
+static inline int
+bond_change_mtu(struct net_device *dev, int newmtu)
+{
+	bonding_t *bond = dev->priv;
+	slave_t *slave;
+	int error;
+
+	dprintk(KERN_INFO "CM: b %p nm %d\n", bond, newmtu);
+	for (slave = bond->prev; slave != (slave_t *)bond;
+	     slave = slave->prev) {
+		dprintk(KERN_INFO "CM: s %p s->p %p c_m %p\n", slave,
+			slave->prev, slave->dev->change_mtu);
+		if (slave->dev->change_mtu) {
+			error = slave->dev->change_mtu(slave->dev, newmtu);
+		} else {
+			slave->dev->mtu = newmtu;
+			error = 0;
+		}
+
+		if (error) {
+			/* If we failed to set the slave's mtu to the new value
+			 * we must abort the operation even in ACTIVE_BACKUP
+			 * mode, because if we allow the backup slaves to have
+			 * different mtu values than the active slave we'll
+			 * need to change their mtu when doing a failover. That
+			 * means changing their mtu from timer context, which
+			 * is probably not a good idea.
+			 */
+			dprintk(KERN_INFO "bond_change_mtu err %d %s\n",
+			       error, slave->dev->name);
+			goto unwind;
+		}
+	}
+
+	dev->mtu = newmtu;
+	return 0;
+
+
+unwind:
+	for (slave = slave->next; slave != bond->next;
+	     slave = slave->next) {
+
+		if (slave->dev->change_mtu) {
+			slave->dev->change_mtu(slave->dev, dev->mtu);
+		} else {
+			slave->dev->mtu = dev->mtu;
+		}
+	}
+
+	return error;
+}
+
 static int bond_event(struct notifier_block *this, unsigned long event, 
 			void *ptr)
 {
@@ -3556,7 +3683,8 @@ static int __init bond_init(struct net_d
 	dev->stop = bond_close;
 	dev->set_multicast_list = set_multicast_list;
 	dev->do_ioctl = bond_ioctl;
-
+	dev->change_mtu = bond_change_mtu;
+	dev->set_mac_address = bond_set_mac_address;
 	dev->tx_queue_len = 0;
 	dev->flags |= IFF_MASTER|IFF_MULTICAST;
 #ifdef CONFIG_NET_FASTROUTE