Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[sfrench/cifs-2.6.git] / drivers / net / bonding / bond_main.c
index 08a4f57cf40966d1ca45cb51c1b8131aa80d65f2..c669554d70bb7c7ba2fe3091ed1c58bd3026229f 100644 (file)
@@ -1217,25 +1217,21 @@ static enum netdev_lag_tx_type bond_lag_tx_type(struct bonding *bond)
        }
 }
 
-static int bond_master_upper_dev_link(struct bonding *bond, struct slave *slave)
+static int bond_master_upper_dev_link(struct bonding *bond, struct slave *slave,
+                                     struct netlink_ext_ack *extack)
 {
        struct netdev_lag_upper_info lag_upper_info;
-       int err;
 
        lag_upper_info.tx_type = bond_lag_tx_type(bond);
-       err = netdev_master_upper_dev_link(slave->dev, bond->dev, slave,
-                                          &lag_upper_info);
-       if (err)
-               return err;
-       rtmsg_ifinfo(RTM_NEWLINK, slave->dev, IFF_SLAVE, GFP_KERNEL);
-       return 0;
+
+       return netdev_master_upper_dev_link(slave->dev, bond->dev, slave,
+                                           &lag_upper_info, extack);
 }
 
 static void bond_upper_dev_unlink(struct bonding *bond, struct slave *slave)
 {
        netdev_upper_dev_unlink(slave->dev, bond->dev);
        slave->dev->flags &= ~IFF_SLAVE;
-       rtmsg_ifinfo(RTM_NEWLINK, slave->dev, IFF_SLAVE, GFP_KERNEL);
 }
 
 static struct slave *bond_alloc_slave(struct bonding *bond)
@@ -1328,7 +1324,8 @@ void bond_lower_state_changed(struct slave *slave)
 }
 
 /* enslave device <slave> to bond device <master> */
-int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
+int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
+                struct netlink_ext_ack *extack)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
@@ -1346,12 +1343,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        /* already in-use? */
        if (netdev_is_rx_handler_busy(slave_dev)) {
+               NL_SET_ERR_MSG(extack, "Device is in use and cannot be enslaved");
                netdev_err(bond_dev,
                           "Error: Device is in use and cannot be enslaved\n");
                return -EBUSY;
        }
 
        if (bond_dev == slave_dev) {
+               NL_SET_ERR_MSG(extack, "Cannot enslave bond to itself.");
                netdev_err(bond_dev, "cannot enslave bond to itself.\n");
                return -EPERM;
        }
@@ -1362,6 +1361,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                netdev_dbg(bond_dev, "%s is NETIF_F_VLAN_CHALLENGED\n",
                           slave_dev->name);
                if (vlan_uses_dev(bond_dev)) {
+                       NL_SET_ERR_MSG(extack, "Can not enslave VLAN challenged device to VLAN enabled bond");
                        netdev_err(bond_dev, "Error: cannot enslave VLAN challenged slave %s on VLAN enabled bond %s\n",
                                   slave_dev->name, bond_dev->name);
                        return -EPERM;
@@ -1381,6 +1381,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         * enslaving it; the old ifenslave will not.
         */
        if (slave_dev->flags & IFF_UP) {
+               NL_SET_ERR_MSG(extack, "Device can not be enslaved while up");
                netdev_err(bond_dev, "%s is up - this may be due to an out of date ifenslave\n",
                           slave_dev->name);
                return -EPERM;
@@ -1421,6 +1422,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                                                 bond_dev);
                }
        } else if (bond_dev->type != slave_dev->type) {
+               NL_SET_ERR_MSG(extack, "Device type is different from other slaves");
                netdev_err(bond_dev, "%s ether type (%d) is different from other slaves (%d), can not enslave it\n",
                           slave_dev->name, slave_dev->type, bond_dev->type);
                return -EINVAL;
@@ -1428,6 +1430,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        if (slave_dev->type == ARPHRD_INFINIBAND &&
            BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
+               NL_SET_ERR_MSG(extack, "Only active-backup mode is supported for infiniband slaves");
                netdev_warn(bond_dev, "Type (%d) supports only active-backup mode\n",
                            slave_dev->type);
                res = -EOPNOTSUPP;
@@ -1443,6 +1446,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                                bond->params.fail_over_mac = BOND_FOM_ACTIVE;
                                netdev_warn(bond_dev, "Setting fail_over_mac to active for active-backup mode\n");
                        } else {
+                               NL_SET_ERR_MSG(extack, "Slave device does not support setting the MAC address, but fail_over_mac is not set to active");
                                netdev_err(bond_dev, "The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n");
                                res = -EOPNOTSUPP;
                                goto err_undo_flags;
@@ -1709,7 +1713,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                goto err_detach;
        }
 
-       res = bond_master_upper_dev_link(bond, new_slave);
+       res = bond_master_upper_dev_link(bond, new_slave, extack);
        if (res) {
                netdev_dbg(bond_dev, "Error %d calling bond_master_upper_dev_link\n", res);
                goto err_unregister;
@@ -2492,7 +2496,8 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
        struct slave *curr_active_slave, *curr_arp_slave;
        unsigned char *arp_ptr;
        __be32 sip, tip;
-       int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP);
+       int is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP);
+       unsigned int alen;
 
        if (!slave_do_arp_validate(bond, slave)) {
                if ((slave_do_arp_validate_only(bond) && is_arp) ||
@@ -3073,7 +3078,16 @@ static int bond_slave_netdev_event(unsigned long event,
                break;
        case NETDEV_UP:
        case NETDEV_CHANGE:
-               bond_update_speed_duplex(slave);
+               /* For 802.3ad mode only:
+                * Getting invalid Speed/Duplex values here will put slave
+                * in weird state. So mark it as link-down for the time
+                * being and let link-monitoring (miimon) set it right when
+                * correct speeds/duplex are available.
+                */
+               if (bond_update_speed_duplex(slave) &&
+                   BOND_MODE(bond) == BOND_MODE_8023AD)
+                       slave->link = BOND_LINK_DOWN;
+
                if (BOND_MODE(bond) == BOND_MODE_8023AD)
                        bond_3ad_adapter_speed_duplex_changed(slave);
                /* Fallthrough */
@@ -3483,7 +3497,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
        switch (cmd) {
        case BOND_ENSLAVE_OLD:
        case SIOCBONDENSLAVE:
-               res = bond_enslave(bond_dev, slave_dev);
+               res = bond_enslave(bond_dev, slave_dev, NULL);
                break;
        case BOND_RELEASE_OLD:
        case SIOCBONDRELEASE: