aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 8e2be24f3fe4..832739f38db4 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 64875859d654..c8bcb59adfdf 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 22ba8632196f..6c023f0f8252 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 573e20f7dba4..0a09ccf68c1c 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 b8a4fd0806af..d9038e328cc1 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{