|
@@ -1604,6 +1604,44 @@ static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#define BOND_INTERSECT_FEATURES \
|
|
|
+ (NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)
|
|
|
+
|
|
|
+/*
|
|
|
+ * Compute the features available to the bonding device by
|
|
|
+ * intersection of all of the slave devices' BOND_INTERSECT_FEATURES.
|
|
|
+ * Call this after attaching or detaching a slave to update the
|
|
|
+ * bond's features.
|
|
|
+ */
|
|
|
+static int bond_compute_features(struct bonding *bond)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ struct slave *slave;
|
|
|
+ struct net_device *bond_dev = bond->dev;
|
|
|
+ int features = bond->bond_features;
|
|
|
+
|
|
|
+ bond_for_each_slave(bond, slave, i) {
|
|
|
+ struct net_device * slave_dev = slave->dev;
|
|
|
+ if (i == 0) {
|
|
|
+ features |= BOND_INTERSECT_FEATURES;
|
|
|
+ }
|
|
|
+ features &=
|
|
|
+ ~(~slave_dev->features & BOND_INTERSECT_FEATURES);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* turn off NETIF_F_SG if we need a csum and h/w can't do it */
|
|
|
+ if ((features & NETIF_F_SG) &&
|
|
|
+ !(features & (NETIF_F_IP_CSUM |
|
|
|
+ NETIF_F_NO_CSUM |
|
|
|
+ NETIF_F_HW_CSUM))) {
|
|
|
+ features &= ~NETIF_F_SG;
|
|
|
+ }
|
|
|
+
|
|
|
+ bond_dev->features = features;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* enslave device <slave> to bond device <master> */
|
|
|
static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
|
|
{
|
|
@@ -1811,6 +1849,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
|
|
|
new_slave->delay = 0;
|
|
|
new_slave->link_failure_count = 0;
|
|
|
|
|
|
+ bond_compute_features(bond);
|
|
|
+
|
|
|
if (bond->params.miimon && !bond->params.use_carrier) {
|
|
|
link_reporting = bond_check_dev_link(bond, slave_dev, 1);
|
|
|
|
|
@@ -2015,7 +2055,7 @@ err_free:
|
|
|
|
|
|
err_undo_flags:
|
|
|
bond_dev->features = old_features;
|
|
|
-
|
|
|
+
|
|
|
return res;
|
|
|
}
|
|
|
|
|
@@ -2100,6 +2140,8 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
|
|
|
/* release the slave from its bond */
|
|
|
bond_detach_slave(bond, slave);
|
|
|
|
|
|
+ bond_compute_features(bond);
|
|
|
+
|
|
|
if (bond->primary_slave == slave) {
|
|
|
bond->primary_slave = NULL;
|
|
|
}
|
|
@@ -2243,6 +2285,8 @@ static int bond_release_all(struct net_device *bond_dev)
|
|
|
bond_alb_deinit_slave(bond, slave);
|
|
|
}
|
|
|
|
|
|
+ bond_compute_features(bond);
|
|
|
+
|
|
|
/* now that the slave is detached, unlock and perform
|
|
|
* all the undo steps that should not be called from
|
|
|
* within a lock.
|
|
@@ -3588,6 +3632,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond
|
|
|
static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev)
|
|
|
{
|
|
|
struct net_device *bond_dev = slave_dev->master;
|
|
|
+ struct bonding *bond = bond_dev->priv;
|
|
|
|
|
|
switch (event) {
|
|
|
case NETDEV_UNREGISTER:
|
|
@@ -3626,6 +3671,9 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
|
|
|
* TODO: handle changing the primary's name
|
|
|
*/
|
|
|
break;
|
|
|
+ case NETDEV_FEAT_CHANGE:
|
|
|
+ bond_compute_features(bond);
|
|
|
+ break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
@@ -4526,6 +4574,11 @@ static inline void bond_set_mode_ops(struct bonding *bond, int mode)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static struct ethtool_ops bond_ethtool_ops = {
|
|
|
+ .get_tx_csum = ethtool_op_get_tx_csum,
|
|
|
+ .get_sg = ethtool_op_get_sg,
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Does not allocate but creates a /proc entry.
|
|
|
* Allowed to fail.
|
|
@@ -4555,6 +4608,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
|
|
|
bond_dev->stop = bond_close;
|
|
|
bond_dev->get_stats = bond_get_stats;
|
|
|
bond_dev->do_ioctl = bond_do_ioctl;
|
|
|
+ bond_dev->ethtool_ops = &bond_ethtool_ops;
|
|
|
bond_dev->set_multicast_list = bond_set_multicast_list;
|
|
|
bond_dev->change_mtu = bond_change_mtu;
|
|
|
bond_dev->set_mac_address = bond_set_mac_address;
|
|
@@ -4591,6 +4645,8 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
|
|
|
NETIF_F_HW_VLAN_RX |
|
|
|
NETIF_F_HW_VLAN_FILTER);
|
|
|
|
|
|
+ bond->bond_features = bond_dev->features;
|
|
|
+
|
|
|
#ifdef CONFIG_PROC_FS
|
|
|
bond_create_proc_entry(bond);
|
|
|
#endif
|