diff options
author | Arthur Kepner <akepner@sgi.com> | 2005-08-23 09:34:53 +0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-08-23 09:34:53 +0400 |
commit | 8531c5ffbca65f6df868637c26e6df6f88bff738 (patch) | |
tree | 2f4fc2f57c83b4d67e06273df4964dc1d724daa5 /drivers/net | |
parent | efcce839360fb3a7b6dedeacaec80f68b0f2d052 (diff) | |
download | linux-8531c5ffbca65f6df868637c26e6df6f88bff738.tar.xz |
[PATCH] bonding: inherit zero-copy flags of slaves
This change allows a bonding device to inherit the "zero-copy"
features of its slave devices.
It was inspired by a couple of previous postings on this topic:
http://marc.theaimsgroup.com/?l=bonding-devel&m=111924607327794&w=2
http://marc.theaimsgroup.com/?l=bonding-devel&m=111925242706297&w=2
and it's largely a combination of the patches that appear in those
emails.
Signed-off-by: Arthur Kepner <akepner@sgi.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 58 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 3 |
2 files changed, 60 insertions, 1 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2c930da90a85..94c9f68dd16b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -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 diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index d27f377b3eeb..388196980862 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -211,6 +211,9 @@ struct bonding { struct bond_params params; struct list_head vlan_list; struct vlan_group *vlgrp; + /* the features the bonding device supports, independently + * of any slaves */ + int bond_features; }; /** |