]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/bonding/bond_main.c
bonding: start slaves with link down for ARP monitor
[karo-tx-linux.git] / drivers / net / bonding / bond_main.c
index 941b4e189adf67391ac06c8effefa820fbd0d5cb..44e6a64eecdd8cb97a6de6fddc0606de4f19419a 100644 (file)
@@ -1726,7 +1726,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        read_lock(&bond->lock);
 
-       new_slave->last_arp_rx = jiffies;
+       new_slave->last_arp_rx = jiffies -
+               (msecs_to_jiffies(bond->params.arp_interval) + 1);
 
        if (bond->params.miimon && !bond->params.use_carrier) {
                link_reporting = bond_check_dev_link(bond, slave_dev, 1);
@@ -1751,22 +1752,30 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        }
 
        /* check for initial state */
-       if (!bond->params.miimon ||
-           (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS)) {
-               if (bond->params.updelay) {
-                       pr_debug("Initial state of slave_dev is BOND_LINK_BACK\n");
-                       new_slave->link  = BOND_LINK_BACK;
-                       new_slave->delay = bond->params.updelay;
+       if (bond->params.miimon) {
+               if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) {
+                       if (bond->params.updelay) {
+                               new_slave->link = BOND_LINK_BACK;
+                               new_slave->delay = bond->params.updelay;
+                       } else {
+                               new_slave->link = BOND_LINK_UP;
+                       }
                } else {
-                       pr_debug("Initial state of slave_dev is BOND_LINK_UP\n");
-                       new_slave->link  = BOND_LINK_UP;
+                       new_slave->link = BOND_LINK_DOWN;
                }
-               new_slave->jiffies = jiffies;
+       } else if (bond->params.arp_interval) {
+               new_slave->link = (netif_carrier_ok(slave_dev) ?
+                       BOND_LINK_UP : BOND_LINK_DOWN);
        } else {
-               pr_debug("Initial state of slave_dev is BOND_LINK_DOWN\n");
-               new_slave->link  = BOND_LINK_DOWN;
+               new_slave->link = BOND_LINK_UP;
        }
 
+       if (new_slave->link != BOND_LINK_DOWN)
+               new_slave->jiffies = jiffies;
+       pr_debug("Initial state of slave_dev is BOND_LINK_%s\n",
+               new_slave->link == BOND_LINK_DOWN ? "DOWN" :
+                       (new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));
+
        bond_update_speed_duplex(new_slave);
 
        if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
@@ -2034,6 +2043,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        write_unlock_bh(&bond->lock);
        unblock_netpoll_tx();
 
+       if (bond->slave_cnt == 0)
+               call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
+
        bond_compute_features(bond);
        if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
            (old_features & NETIF_F_VLAN_CHALLENGED))
@@ -3007,7 +3019,11 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
                                           trans_start + delta_in_ticks)) ||
                            bond->curr_active_slave != slave) {
                                slave->link = BOND_LINK_UP;
-                               bond->current_arp_slave = NULL;
+                               if (bond->current_arp_slave) {
+                                       bond_set_slave_inactive_flags(
+                                               bond->current_arp_slave);
+                                       bond->current_arp_slave = NULL;
+                               }
 
                                pr_info("%s: link status definitely up for interface %s.\n",
                                        bond->dev->name, slave->dev->name);
@@ -3701,17 +3717,52 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
        read_unlock(&bond->lock);
 }
 
-static int bond_neigh_setup(struct net_device *dev, struct neigh_parms *parms)
+static int bond_neigh_init(struct neighbour *n)
 {
-       struct bonding *bond = netdev_priv(dev);
+       struct bonding *bond = netdev_priv(n->dev);
        struct slave *slave = bond->first_slave;
+       const struct net_device_ops *slave_ops;
+       struct neigh_parms parms;
+       int ret;
+
+       if (!slave)
+               return 0;
+
+       slave_ops = slave->dev->netdev_ops;
+
+       if (!slave_ops->ndo_neigh_setup)
+               return 0;
+
+       parms.neigh_setup = NULL;
+       parms.neigh_cleanup = NULL;
+       ret = slave_ops->ndo_neigh_setup(slave->dev, &parms);
+       if (ret)
+               return ret;
+
+       /*
+        * Assign slave's neigh_cleanup to neighbour in case cleanup is called
+        * after the last slave has been detached.  Assumes that all slaves
+        * utilize the same neigh_cleanup (true at this writing as only user
+        * is ipoib).
+        */
+       n->parms->neigh_cleanup = parms.neigh_cleanup;
+
+       if (!parms.neigh_setup)
+               return 0;
+
+       return parms.neigh_setup(n);
+}
+
+/*
+ * The bonding ndo_neigh_setup is called at init time beofre any
+ * slave exists. So we must declare proxy setup function which will
+ * be used at run time to resolve the actual slave neigh param setup.
+ */
+static int bond_neigh_setup(struct net_device *dev,
+                           struct neigh_parms *parms)
+{
+       parms->neigh_setup   = bond_neigh_init;
 
-       if (slave) {
-               const struct net_device_ops *slave_ops
-                       = slave->dev->netdev_ops;
-               if (slave_ops->ndo_neigh_setup)
-                       return slave_ops->ndo_neigh_setup(slave->dev, parms);
-       }
        return 0;
 }
 
@@ -4778,12 +4829,9 @@ static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
        return 0;
 }
 
-static int bond_get_tx_queues(struct net *net, struct nlattr *tb[],
-                             unsigned int *num_queues,
-                             unsigned int *real_num_queues)
+static int bond_get_tx_queues(struct net *net, struct nlattr *tb[])
 {
-       *num_queues = tx_queues;
-       return 0;
+       return tx_queues;
 }
 
 static struct rtnl_link_ops bond_link_ops __read_mostly = {