aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-08-10 18:47:58 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-08-14 01:52:14 -0400
commit7f353bf29e162459f2f1e2ca25e41011fae65241 (patch)
tree8df6d6c66b69f18d521f76018ff98706e4e2a1b3 /net
parentf71417614d63932cf56ed98a0947568d6259d11e (diff)
[NET]: Share correct feature code between bridging and bonding
http://bugzilla.kernel.org/show_bug.cgi?id=8797 shows that the bonding driver may produce bogus combinations of the checksum flags and SG/TSO. For example, if you bond devices with NETIF_F_HW_CSUM and NETIF_F_IP_CSUM you'll end up with a bonding device that has neither flag set. If both have TSO then this produces an illegal combination. The bridge device on the other hand has the correct code to deal with this. In fact, the same code can be used for both. So this patch moves that logic into net/core/dev.c and uses it for both bonding and bridging. In the process I've made small adjustments such as only setting GSO_ROBUST if at least one constituent device supports it. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_if.c36
-rw-r--r--net/core/dev.c39
3 files changed, 44 insertions, 33 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 5e1892d8d874..0eded176ce99 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 dev->priv_flags = IFF_EBRIDGE; 179 dev->priv_flags = IFF_EBRIDGE;
180 180
181 dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | 181 dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
182 NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST; 182 NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX;
183} 183}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index b40dada002bf..749f0e8f541d 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -349,43 +349,15 @@ int br_min_mtu(const struct net_bridge *br)
349void br_features_recompute(struct net_bridge *br) 349void br_features_recompute(struct net_bridge *br)
350{ 350{
351 struct net_bridge_port *p; 351 struct net_bridge_port *p;
352 unsigned long features, checksum; 352 unsigned long features;
353 353
354 checksum = br->feature_mask & NETIF_F_ALL_CSUM ? NETIF_F_NO_CSUM : 0; 354 features = br->feature_mask;
355 features = br->feature_mask & ~NETIF_F_ALL_CSUM;
356 355
357 list_for_each_entry(p, &br->port_list, list) { 356 list_for_each_entry(p, &br->port_list, list) {
358 unsigned long feature = p->dev->features; 357 features = netdev_compute_features(features, p->dev->features);
359
360 /* if device needs checksumming, downgrade to hw checksumming */
361 if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
362 checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
363
364 /* if device can't do all checksum, downgrade to ipv4/ipv6 */
365 if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
366 checksum ^= NETIF_F_HW_CSUM
367 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
368
369 if (checksum & NETIF_F_IPV6_CSUM && !(feature & NETIF_F_IPV6_CSUM))
370 checksum &= ~NETIF_F_IPV6_CSUM;
371
372 if (!(feature & NETIF_F_IP_CSUM))
373 checksum = 0;
374
375 if (feature & NETIF_F_GSO)
376 feature |= NETIF_F_GSO_SOFTWARE;
377 feature |= NETIF_F_GSO;
378
379 features &= feature;
380 } 358 }
381 359
382 if (!(checksum & NETIF_F_ALL_CSUM)) 360 br->dev->features = features;
383 features &= ~NETIF_F_SG;
384 if (!(features & NETIF_F_SG))
385 features &= ~NETIF_F_GSO_MASK;
386
387 br->dev->features = features | checksum | NETIF_F_LLTX |
388 NETIF_F_GSO_ROBUST;
389} 361}
390 362
391/* called with RTNL */ 363/* called with RTNL */
diff --git a/net/core/dev.c b/net/core/dev.c
index 6cc8a70350ac..a76021c71207 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3993,6 +3993,45 @@ static int __init netdev_dma_register(void)
3993static int __init netdev_dma_register(void) { return -ENODEV; } 3993static int __init netdev_dma_register(void) { return -ENODEV; }
3994#endif /* CONFIG_NET_DMA */ 3994#endif /* CONFIG_NET_DMA */
3995 3995
3996/**
3997 * netdev_compute_feature - compute conjunction of two feature sets
3998 * @all: first feature set
3999 * @one: second feature set
4000 *
4001 * Computes a new feature set after adding a device with feature set
4002 * @one to the master device with current feature set @all. Returns
4003 * the new feature set.
4004 */
4005int netdev_compute_features(unsigned long all, unsigned long one)
4006{
4007 /* if device needs checksumming, downgrade to hw checksumming */
4008 if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM))
4009 all ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
4010
4011 /* if device can't do all checksum, downgrade to ipv4/ipv6 */
4012 if (all & NETIF_F_HW_CSUM && !(one & NETIF_F_HW_CSUM))
4013 all ^= NETIF_F_HW_CSUM
4014 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
4015
4016 if (one & NETIF_F_GSO)
4017 one |= NETIF_F_GSO_SOFTWARE;
4018 one |= NETIF_F_GSO;
4019
4020 /* If even one device supports robust GSO, enable it for all. */
4021 if (one & NETIF_F_GSO_ROBUST)
4022 all |= NETIF_F_GSO_ROBUST;
4023
4024 all &= one | NETIF_F_LLTX;
4025
4026 if (!(all & NETIF_F_ALL_CSUM))
4027 all &= ~NETIF_F_SG;
4028 if (!(all & NETIF_F_SG))
4029 all &= ~NETIF_F_GSO_MASK;
4030
4031 return all;
4032}
4033EXPORT_SYMBOL(netdev_compute_features);
4034
3996/* 4035/*
3997 * Initialize the DEV module. At boot time this walks the device list and 4036 * Initialize the DEV module. At boot time this walks the device list and
3998 * unhooks any devices that fail to initialise (normally hardware not 4037 * unhooks any devices that fail to initialise (normally hardware not