aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-10-23 04:11:29 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-23 04:11:29 -0400
commitb63365a2d60268a3988285d6c3c6003d7066f93a (patch)
tree85bd8f91f3de954c697aa44544b4adf191e7f5aa
parent2e3f92dad6bdbee796274bae5c1c50a6ddd31cbb (diff)
net: Fix disjunct computation of netdev features
My change commit e2a6b85247aacc52d6ba0d9b37a99b8d1a3e0d83 net: Enable TSO if supported by at least one device didn't do what was intended because the netdev_compute_features function was designed for conjunctions. So what happened was that it would simply take the TSO status of the last constituent device. This patch extends it to support both conjunctions and disjunctions under the new name of netdev_increment_features. It also adds a new function netdev_fix_features which does the sanity checking that usually occurs upon registration. This ensures that the computation doesn't result in an illegal combination since this checking is absent when the change is initiated via ethtool. The two users of netdev_compute_features have been converted. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c16
-rw-r--r--include/linux/netdevice.h12
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_if.c14
-rw-r--r--net/core/dev.c135
5 files changed, 104 insertions, 75 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 8e2be24f3fe..832739f38db 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1341,18 +1341,24 @@ static int bond_compute_features(struct bonding *bond)
1341 int i; 1341 int i;
1342 1342
1343 features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); 1343 features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
1344 features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | 1344 features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM;
1345 NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; 1345
1346 if (!bond->first_slave)
1347 goto done;
1348
1349 features &= ~NETIF_F_ONE_FOR_ALL;
1346 1350
1347 bond_for_each_slave(bond, slave, i) { 1351 bond_for_each_slave(bond, slave, i) {
1348 features = netdev_compute_features(features, 1352 features = netdev_increment_features(features,
1349 slave->dev->features); 1353 slave->dev->features,
1354 NETIF_F_ONE_FOR_ALL);
1350 if (slave->dev->hard_header_len > max_hard_header_len) 1355 if (slave->dev->hard_header_len > max_hard_header_len)
1351 max_hard_header_len = slave->dev->hard_header_len; 1356 max_hard_header_len = slave->dev->hard_header_len;
1352 } 1357 }
1353 1358
1359done:
1354 features |= (bond_dev->features & BOND_VLAN_FEATURES); 1360 features |= (bond_dev->features & BOND_VLAN_FEATURES);
1355 bond_dev->features = features; 1361 bond_dev->features = netdev_fix_features(features, NULL);
1356 bond_dev->hard_header_len = max_hard_header_len; 1362 bond_dev->hard_header_len = max_hard_header_len;
1357 1363
1358 return 0; 1364 return 0;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 64875859d65..c8bcb59adfd 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -541,6 +541,14 @@ struct net_device
541#define NETIF_F_V6_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM) 541#define NETIF_F_V6_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
542#define NETIF_F_ALL_CSUM (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM) 542#define NETIF_F_ALL_CSUM (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
543 543
544 /*
545 * If one device supports one of these features, then enable them
546 * for all in netdev_increment_features.
547 */
548#define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \
549 NETIF_F_SG | NETIF_F_HIGHDMA | \
550 NETIF_F_FRAGLIST)
551
544 /* Interface index. Unique device identifier */ 552 /* Interface index. Unique device identifier */
545 int ifindex; 553 int ifindex;
546 int iflink; 554 int iflink;
@@ -1698,7 +1706,9 @@ extern char *netdev_drivername(const struct net_device *dev, char *buffer, int l
1698 1706
1699extern void linkwatch_run_queue(void); 1707extern void linkwatch_run_queue(void);
1700 1708
1701extern int netdev_compute_features(unsigned long all, unsigned long one); 1709unsigned long netdev_increment_features(unsigned long all, unsigned long one,
1710 unsigned long mask);
1711unsigned long netdev_fix_features(unsigned long features, const char *name);
1702 1712
1703static inline int net_gso_ok(int features, int gso_type) 1713static inline int net_gso_ok(int features, int gso_type)
1704{ 1714{
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 22ba8632196..6c023f0f825 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -179,5 +179,5 @@ void br_dev_setup(struct net_device *dev)
179 179
180 dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | 180 dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
181 NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX | 181 NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
182 NETIF_F_NETNS_LOCAL; 182 NETIF_F_NETNS_LOCAL | NETIF_F_GSO;
183} 183}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 573e20f7dba..0a09ccf68c1 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -347,15 +347,21 @@ int br_min_mtu(const struct net_bridge *br)
347void br_features_recompute(struct net_bridge *br) 347void br_features_recompute(struct net_bridge *br)
348{ 348{
349 struct net_bridge_port *p; 349 struct net_bridge_port *p;
350 unsigned long features; 350 unsigned long features, mask;
351 351
352 features = br->feature_mask; 352 features = mask = br->feature_mask;
353 if (list_empty(&br->port_list))
354 goto done;
355
356 features &= ~NETIF_F_ONE_FOR_ALL;
353 357
354 list_for_each_entry(p, &br->port_list, list) { 358 list_for_each_entry(p, &br->port_list, list) {
355 features = netdev_compute_features(features, p->dev->features); 359 features = netdev_increment_features(features,
360 p->dev->features, mask);
356 } 361 }
357 362
358 br->dev->features = features; 363done:
364 br->dev->features = netdev_fix_features(features, NULL);
359} 365}
360 366
361/* called with RTNL */ 367/* called with RTNL */
diff --git a/net/core/dev.c b/net/core/dev.c
index b8a4fd0806a..d9038e328cc 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3947,6 +3947,46 @@ static void netdev_init_queue_locks(struct net_device *dev)
3947 __netdev_init_queue_locks_one(dev, &dev->rx_queue, NULL); 3947 __netdev_init_queue_locks_one(dev, &dev->rx_queue, NULL);
3948} 3948}
3949 3949
3950unsigned long netdev_fix_features(unsigned long features, const char *name)
3951{
3952 /* Fix illegal SG+CSUM combinations. */
3953 if ((features & NETIF_F_SG) &&
3954 !(features & NETIF_F_ALL_CSUM)) {
3955 if (name)
3956 printk(KERN_NOTICE "%s: Dropping NETIF_F_SG since no "
3957 "checksum feature.\n", name);
3958 features &= ~NETIF_F_SG;
3959 }
3960
3961 /* TSO requires that SG is present as well. */
3962 if ((features & NETIF_F_TSO) && !(features & NETIF_F_SG)) {
3963 if (name)
3964 printk(KERN_NOTICE "%s: Dropping NETIF_F_TSO since no "
3965 "SG feature.\n", name);
3966 features &= ~NETIF_F_TSO;
3967 }
3968
3969 if (features & NETIF_F_UFO) {
3970 if (!(features & NETIF_F_GEN_CSUM)) {
3971 if (name)
3972 printk(KERN_ERR "%s: Dropping NETIF_F_UFO "
3973 "since no NETIF_F_HW_CSUM feature.\n",
3974 name);
3975 features &= ~NETIF_F_UFO;
3976 }
3977
3978 if (!(features & NETIF_F_SG)) {
3979 if (name)
3980 printk(KERN_ERR "%s: Dropping NETIF_F_UFO "
3981 "since no NETIF_F_SG feature.\n", name);
3982 features &= ~NETIF_F_UFO;
3983 }
3984 }
3985
3986 return features;
3987}
3988EXPORT_SYMBOL(netdev_fix_features);
3989
3950/** 3990/**
3951 * register_netdevice - register a network device 3991 * register_netdevice - register a network device
3952 * @dev: device to register 3992 * @dev: device to register
@@ -4032,36 +4072,7 @@ int register_netdevice(struct net_device *dev)
4032 dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM); 4072 dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM);
4033 } 4073 }
4034 4074
4035 4075 dev->features = netdev_fix_features(dev->features, dev->name);
4036 /* Fix illegal SG+CSUM combinations. */
4037 if ((dev->features & NETIF_F_SG) &&
4038 !(dev->features & NETIF_F_ALL_CSUM)) {
4039 printk(KERN_NOTICE "%s: Dropping NETIF_F_SG since no checksum feature.\n",
4040 dev->name);
4041 dev->features &= ~NETIF_F_SG;
4042 }
4043
4044 /* TSO requires that SG is present as well. */
4045 if ((dev->features & NETIF_F_TSO) &&
4046 !(dev->features & NETIF_F_SG)) {
4047 printk(KERN_NOTICE "%s: Dropping NETIF_F_TSO since no SG feature.\n",
4048 dev->name);
4049 dev->features &= ~NETIF_F_TSO;
4050 }
4051 if (dev->features & NETIF_F_UFO) {
4052 if (!(dev->features & NETIF_F_HW_CSUM)) {
4053 printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no "
4054 "NETIF_F_HW_CSUM feature.\n",
4055 dev->name);
4056 dev->features &= ~NETIF_F_UFO;
4057 }
4058 if (!(dev->features & NETIF_F_SG)) {
4059 printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no "
4060 "NETIF_F_SG feature.\n",
4061 dev->name);
4062 dev->features &= ~NETIF_F_UFO;
4063 }
4064 }
4065 4076
4066 /* Enable software GSO if SG is supported. */ 4077 /* Enable software GSO if SG is supported. */
4067 if (dev->features & NETIF_F_SG) 4078 if (dev->features & NETIF_F_SG)
@@ -4700,49 +4711,45 @@ static int __init netdev_dma_register(void) { return -ENODEV; }
4700#endif /* CONFIG_NET_DMA */ 4711#endif /* CONFIG_NET_DMA */
4701 4712
4702/** 4713/**
4703 * netdev_compute_feature - compute conjunction of two feature sets 4714 * netdev_increment_features - increment feature set by one
4704 * @all: first feature set 4715 * @all: current feature set
4705 * @one: second feature set 4716 * @one: new feature set
4717 * @mask: mask feature set
4706 * 4718 *
4707 * Computes a new feature set after adding a device with feature set 4719 * Computes a new feature set after adding a device with feature set
4708 * @one to the master device with current feature set @all. Returns 4720 * @one to the master device with current feature set @all. Will not
4709 * the new feature set. 4721 * enable anything that is off in @mask. Returns the new feature set.
4710 */ 4722 */
4711int netdev_compute_features(unsigned long all, unsigned long one) 4723unsigned long netdev_increment_features(unsigned long all, unsigned long one,
4712{ 4724 unsigned long mask)
4713 /* if device needs checksumming, downgrade to hw checksumming */ 4725{
4714 if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM)) 4726 /* If device needs checksumming, downgrade to it. */
4715 all ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM; 4727 if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM))
4716 4728 all ^= NETIF_F_NO_CSUM | (one & NETIF_F_ALL_CSUM);
4717 /* if device can't do all checksum, downgrade to ipv4/ipv6 */ 4729 else if (mask & NETIF_F_ALL_CSUM) {
4718 if (all & NETIF_F_HW_CSUM && !(one & NETIF_F_HW_CSUM)) 4730 /* If one device supports v4/v6 checksumming, set for all. */
4719 all ^= NETIF_F_HW_CSUM 4731 if (one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM) &&
4720 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; 4732 !(all & NETIF_F_GEN_CSUM)) {
4721 4733 all &= ~NETIF_F_ALL_CSUM;
4722 if (one & NETIF_F_GSO) 4734 all |= one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
4723 one |= NETIF_F_GSO_SOFTWARE; 4735 }
4724 one |= NETIF_F_GSO;
4725
4726 /*
4727 * If even one device supports a GSO protocol with software fallback,
4728 * enable it for all.
4729 */
4730 all |= one & NETIF_F_GSO_SOFTWARE;
4731 4736
4732 /* If even one device supports robust GSO, enable it for all. */ 4737 /* If one device supports hw checksumming, set for all. */
4733 if (one & NETIF_F_GSO_ROBUST) 4738 if (one & NETIF_F_GEN_CSUM && !(all & NETIF_F_GEN_CSUM)) {
4734 all |= NETIF_F_GSO_ROBUST; 4739 all &= ~NETIF_F_ALL_CSUM;
4740 all |= NETIF_F_HW_CSUM;
4741 }
4742 }
4735 4743
4736 all &= one | NETIF_F_LLTX; 4744 one |= NETIF_F_ALL_CSUM;
4737 4745
4738 if (!(all & NETIF_F_ALL_CSUM)) 4746 one |= all & NETIF_F_ONE_FOR_ALL;
4739 all &= ~NETIF_F_SG; 4747 all &= one | NETIF_F_LLTX | NETIF_F_GSO;
4740 if (!(all & NETIF_F_SG)) 4748 all |= one & mask & NETIF_F_ONE_FOR_ALL;
4741 all &= ~NETIF_F_GSO_MASK;
4742 4749
4743 return all; 4750 return all;
4744} 4751}
4745EXPORT_SYMBOL(netdev_compute_features); 4752EXPORT_SYMBOL(netdev_increment_features);
4746 4753
4747static struct hlist_head *netdev_create_hash(void) 4754static struct hlist_head *netdev_create_hash(void)
4748{ 4755{