net/bonding: Optionally allow ethernet slaves to keep own MAC
[safe/jmp/linux-2.6] / drivers / net / bonding / bond_main.c
index 6ae4593..db80f24 100644 (file)
@@ -98,6 +98,7 @@ static char *xmit_hash_policy = NULL;
 static int arp_interval = BOND_LINK_ARP_INTERV;
 static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
 static char *arp_validate = NULL;
+static int fail_over_mac = 0;
 struct bond_params bonding_defaults;
 
 module_param(max_bonds, int, 0);
@@ -131,6 +132,8 @@ module_param_array(arp_ip_target, charp, NULL, 0);
 MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
 module_param(arp_validate, charp, 0);
 MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
+module_param(fail_over_mac, int, 0);
+MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC.  0 of off (default), 1 for on.");
 
 /*----------------------------- Global variables ----------------------------*/
 
@@ -1096,7 +1099,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                if (new_active) {
                        bond_set_slave_active_flags(new_active);
                }
-               bond_send_gratuitous_arp(bond);
+
+               /* when bonding does not set the slave MAC address, the bond MAC
+                * address is the one of the active slave.
+                */
+               if (new_active && bond->params.fail_over_mac)
+                       memcpy(bond->dev->dev_addr,  new_active->dev->dev_addr,
+                               new_active->dev->addr_len);
+               if (bond->curr_active_slave &&
+                       test_bit(__LINK_STATE_LINKWATCH_PENDING,
+                                       &bond->curr_active_slave->dev->state)) {
+                       dprintk("delaying gratuitous arp on %s\n",
+                               bond->curr_active_slave->dev->name);
+                       bond->send_grat_arp = 1;
+               } else
+                       bond_send_gratuitous_arp(bond);
        }
 }
 
@@ -1217,7 +1234,8 @@ static int bond_compute_features(struct bonding *bond)
        struct slave *slave;
        struct net_device *bond_dev = bond->dev;
        unsigned long features = bond_dev->features;
-       unsigned short max_hard_header_len = ETH_HLEN;
+       unsigned short max_hard_header_len = max((u16)ETH_HLEN,
+                                               bond_dev->hard_header_len);
        int i;
 
        features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
@@ -1242,6 +1260,8 @@ static int bond_compute_features(struct bonding *bond)
 static void bond_setup_by_slave(struct net_device *bond_dev,
                                struct net_device *slave_dev)
 {
+       struct bonding *bond = bond_dev->priv;
+
        bond_dev->neigh_setup           = slave_dev->neigh_setup;
 
        bond_dev->type              = slave_dev->type;
@@ -1250,6 +1270,7 @@ static void bond_setup_by_slave(struct net_device *bond_dev,
 
        memcpy(bond_dev->broadcast, slave_dev->broadcast,
                slave_dev->addr_len);
+       bond->setup_by_slave = 1;
 }
 
 /* enslave device <slave> to bond device <master> */
@@ -1272,8 +1293,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        /* bond must be initialized by bond_open() before enslaving */
        if (!(bond_dev->flags & IFF_UP)) {
-               dprintk("Error, master_dev is not up\n");
-               return -EPERM;
+               printk(KERN_WARNING DRV_NAME
+                       " %s: master_dev is not up in bond_enslave\n",
+                       bond_dev->name);
        }
 
        /* already enslaved */
@@ -1346,13 +1368,22 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        }
 
        if (slave_dev->set_mac_address == NULL) {
-               printk(KERN_ERR DRV_NAME
-                       ": %s: Error: The slave device you specified does "
-                       "not support setting the MAC address. "
-                       "Your kernel likely does not support slave "
-                       "devices.\n", bond_dev->name);
-               res = -EOPNOTSUPP;
-               goto err_undo_flags;
+               if (bond->slave_cnt == 0) {
+                       printk(KERN_WARNING DRV_NAME
+                              ": %s: Warning: The first slave device "
+                              "specified does not support setting the MAC "
+                              "address. Enabling the fail_over_mac option.",
+                              bond_dev->name);
+                       bond->params.fail_over_mac = 1;
+               } else if (!bond->params.fail_over_mac) {
+                       printk(KERN_ERR DRV_NAME
+                               ": %s: Error: The slave device specified "
+                               "does not support setting the MAC address, "
+                               "but fail_over_mac is not enabled.\n"
+                               , bond_dev->name);
+                       res = -EOPNOTSUPP;
+                       goto err_undo_flags;
+               }
        }
 
        new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
@@ -1373,16 +1404,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         */
        memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN);
 
-       /*
-        * Set slave to master's mac address.  The application already
-        * set the master's mac address to that of the first slave
-        */
-       memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
-       addr.sa_family = slave_dev->type;
-       res = dev_set_mac_address(slave_dev, &addr);
-       if (res) {
-               dprintk("Error %d calling set_mac_address\n", res);
-               goto err_free;
+       if (!bond->params.fail_over_mac) {
+               /*
+                * Set slave to master's mac address.  The application already
+                * set the master's mac address to that of the first slave
+                */
+               memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
+               addr.sa_family = slave_dev->type;
+               res = dev_set_mac_address(slave_dev, &addr);
+               if (res) {
+                       dprintk("Error %d calling set_mac_address\n", res);
+                       goto err_free;
+               }
        }
 
        res = netdev_set_master(slave_dev, bond_dev);
@@ -1607,9 +1640,11 @@ err_close:
        dev_close(slave_dev);
 
 err_restore_mac:
-       memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
-       addr.sa_family = slave_dev->type;
-       dev_set_mac_address(slave_dev, &addr);
+       if (!bond->params.fail_over_mac) {
+               memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
+               addr.sa_family = slave_dev->type;
+               dev_set_mac_address(slave_dev, &addr);
+       }
 
 err_free:
        kfree(new_slave);
@@ -1782,10 +1817,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        /* close slave before restoring its mac address */
        dev_close(slave_dev);
 
-       /* restore original ("permanent") mac address */
-       memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
-       addr.sa_family = slave_dev->type;
-       dev_set_mac_address(slave_dev, &addr);
+       if (!bond->params.fail_over_mac) {
+               /* restore original ("permanent") mac address */
+               memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+               addr.sa_family = slave_dev->type;
+               dev_set_mac_address(slave_dev, &addr);
+       }
 
        slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
                                   IFF_SLAVE_INACTIVE | IFF_BONDING |
@@ -1797,6 +1834,35 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 }
 
 /*
+* Destroy a bonding device.
+* Must be under rtnl_lock when this function is called.
+*/
+void bond_destroy(struct bonding *bond)
+{
+       bond_deinit(bond->dev);
+       bond_destroy_sysfs_entry(bond);
+       unregister_netdevice(bond->dev);
+}
+
+/*
+* First release a slave and than destroy the bond if no more slaves iare left.
+* Must be under rtnl_lock when this function is called.
+*/
+int  bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev)
+{
+       struct bonding *bond = bond_dev->priv;
+       int ret;
+
+       ret = bond_release(bond_dev, slave_dev);
+       if ((ret == 0) && (bond->slave_cnt == 0)) {
+               printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n",
+                      bond_dev->name, bond_dev->name);
+               bond_destroy(bond);
+       }
+       return ret;
+}
+
+/*
  * This function releases all slaves.
  */
 static int bond_release_all(struct net_device *bond_dev)
@@ -1872,10 +1938,12 @@ static int bond_release_all(struct net_device *bond_dev)
                /* close slave before restoring its mac address */
                dev_close(slave_dev);
 
-               /* restore original ("permanent") mac address*/
-               memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
-               addr.sa_family = slave_dev->type;
-               dev_set_mac_address(slave_dev, &addr);
+               if (!bond->params.fail_over_mac) {
+                       /* restore original ("permanent") mac address*/
+                       memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+                       addr.sa_family = slave_dev->type;
+                       dev_set_mac_address(slave_dev, &addr);
+               }
 
                slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
                                           IFF_SLAVE_INACTIVE);
@@ -2046,6 +2114,17 @@ void bond_mii_monitor(struct net_device *bond_dev)
         * program could monitor the link itself if needed.
         */
 
+       if (bond->send_grat_arp) {
+               if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING,
+                               &bond->curr_active_slave->dev->state))
+                       dprintk("Needs to send gratuitous arp but not yet\n");
+               else {
+                       dprintk("sending delayed gratuitous arp on on %s\n",
+                               bond->curr_active_slave->dev->name);
+                       bond_send_gratuitous_arp(bond);
+                       bond->send_grat_arp = 0;
+               }
+       }
        read_lock(&bond->curr_slave_lock);
        oldcurrent = bond->curr_active_slave;
        read_unlock(&bond->curr_slave_lock);
@@ -2447,7 +2526,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
 
        if (bond->master_ip) {
                bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
-                                 bond->master_ip, 0);
+                               bond->master_ip, 0);
        }
 
        list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
@@ -2984,9 +3063,15 @@ static void bond_info_show_master(struct seq_file *seq)
        curr = bond->curr_active_slave;
        read_unlock(&bond->curr_slave_lock);
 
-       seq_printf(seq, "Bonding Mode: %s\n",
+       seq_printf(seq, "Bonding Mode: %s",
                   bond_mode_name(bond->params.mode));
 
+       if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
+           bond->params.fail_over_mac)
+               seq_printf(seq, " (fail_over_mac)");
+
+       seq_printf(seq, "\n");
+
        if (bond->params.mode == BOND_MODE_XOR ||
                bond->params.mode == BOND_MODE_8023AD) {
                seq_printf(seq, "Transmit Hash Policy: %s (%d)\n",
@@ -3281,6 +3366,11 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
                 * ... Or is it this?
                 */
                break;
+       case NETDEV_GOING_DOWN:
+               dprintk("slave %s is going down\n", slave_dev->name);
+               if (bond->setup_by_slave)
+                       bond_release_and_destroy(bond_dev, slave_dev);
+               break;
        case NETDEV_CHANGEMTU:
                /*
                 * TODO: Should slaves be allowed to
@@ -3913,6 +4003,13 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 
        dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
 
+       /*
+        * If fail_over_mac is enabled, do nothing and return success.
+        * Returning an error causes ifenslave to fail.
+        */
+       if (bond->params.fail_over_mac)
+               return 0;
+
        if (!is_valid_ether_addr(sa->sa_data)) {
                return -EADDRNOTAVAIL;
        }
@@ -4250,6 +4347,8 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
        bond->current_arp_slave = NULL;
        bond->primary_slave = NULL;
        bond->dev = bond_dev;
+       bond->send_grat_arp = 0;
+       bond->setup_by_slave = 0;
        INIT_LIST_HEAD(&bond->vlan_list);
 
        /* Initialize the device entry points */
@@ -4298,7 +4397,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
 #ifdef CONFIG_PROC_FS
        bond_create_proc_entry(bond);
 #endif
-
        list_add_tail(&bond->bond_list, &bond_dev_list);
 
        return 0;
@@ -4632,6 +4730,11 @@ static int bond_check_params(struct bond_params *params)
                primary = NULL;
        }
 
+       if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP))
+               printk(KERN_WARNING DRV_NAME
+                      ": Warning: fail_over_mac only affects "
+                      "active-backup mode.\n");
+
        /* fill params struct with the proper values */
        params->mode = bond_mode;
        params->xmit_policy = xmit_hashtype;
@@ -4643,6 +4746,7 @@ static int bond_check_params(struct bond_params *params)
        params->use_carrier = use_carrier;
        params->lacp_fast = lacp_fast;
        params->primary[0] = 0;
+       params->fail_over_mac = fail_over_mac;
 
        if (primary) {
                strncpy(params->primary, primary, IFNAMSIZ);