diff options
-rw-r--r-- | drivers/net/bonding/bond_main.c | 16 | ||||
-rw-r--r-- | include/linux/netdevice.h | 12 | ||||
-rw-r--r-- | net/bridge/br_device.c | 2 | ||||
-rw-r--r-- | net/bridge/br_if.c | 14 | ||||
-rw-r--r-- | net/core/dev.c | 135 |
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 | ||
1359 | done: | ||
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 | ||
1699 | extern void linkwatch_run_queue(void); | 1707 | extern void linkwatch_run_queue(void); |
1700 | 1708 | ||
1701 | extern int netdev_compute_features(unsigned long all, unsigned long one); | 1709 | unsigned long netdev_increment_features(unsigned long all, unsigned long one, |
1710 | unsigned long mask); | ||
1711 | unsigned long netdev_fix_features(unsigned long features, const char *name); | ||
1702 | 1712 | ||
1703 | static inline int net_gso_ok(int features, int gso_type) | 1713 | static 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) | |||
347 | void br_features_recompute(struct net_bridge *br) | 347 | void 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; | 363 | done: |
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 | ||
3950 | unsigned 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 | } | ||
3988 | EXPORT_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 | */ |
4711 | int netdev_compute_features(unsigned long all, unsigned long one) | 4723 | unsigned 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 | } |
4745 | EXPORT_SYMBOL(netdev_compute_features); | 4752 | EXPORT_SYMBOL(netdev_increment_features); |
4746 | 4753 | ||
4747 | static struct hlist_head *netdev_create_hash(void) | 4754 | static struct hlist_head *netdev_create_hash(void) |
4748 | { | 4755 | { |