Skip to content

Commit b63365a

Browse files
herbertxdavem330
authored andcommitted
net: Fix disjunct computation of netdev features
My change commit e2a6b85 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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2e3f92d commit b63365a

File tree

5 files changed

+104
-75
lines changed

5 files changed

+104
-75
lines changed

drivers/net/bonding/bond_main.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,18 +1341,24 @@ static int bond_compute_features(struct bonding *bond)
13411341
int i;
13421342

13431343
features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
1344-
features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
1345-
NETIF_F_GSO_MASK | NETIF_F_NO_CSUM;
1344+
features |= 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;
13461350

13471351
bond_for_each_slave(bond, slave, i) {
1348-
features = netdev_compute_features(features,
1349-
slave->dev->features);
1352+
features = netdev_increment_features(features,
1353+
slave->dev->features,
1354+
NETIF_F_ONE_FOR_ALL);
13501355
if (slave->dev->hard_header_len > max_hard_header_len)
13511356
max_hard_header_len = slave->dev->hard_header_len;
13521357
}
13531358

1359+
done:
13541360
features |= (bond_dev->features & BOND_VLAN_FEATURES);
1355-
bond_dev->features = features;
1361+
bond_dev->features = netdev_fix_features(features, NULL);
13561362
bond_dev->hard_header_len = max_hard_header_len;
13571363

13581364
return 0;

include/linux/netdevice.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,14 @@ struct net_device
541541
#define NETIF_F_V6_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
542542
#define NETIF_F_ALL_CSUM (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
543543

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+
544552
/* Interface index. Unique device identifier */
545553
int ifindex;
546554
int iflink;
@@ -1698,7 +1706,9 @@ extern char *netdev_drivername(const struct net_device *dev, char *buffer, int l
16981706

16991707
extern void linkwatch_run_queue(void);
17001708

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);
17021712

17031713
static inline int net_gso_ok(int features, int gso_type)
17041714
{

net/bridge/br_device.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,5 +179,5 @@ void br_dev_setup(struct net_device *dev)
179179

180180
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
181181
NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
182-
NETIF_F_NETNS_LOCAL;
182+
NETIF_F_NETNS_LOCAL | NETIF_F_GSO;
183183
}

net/bridge/br_if.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -347,15 +347,21 @@ int br_min_mtu(const struct net_bridge *br)
347347
void br_features_recompute(struct net_bridge *br)
348348
{
349349
struct net_bridge_port *p;
350-
unsigned long features;
350+
unsigned long features, mask;
351351

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;
353357

354358
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);
356361
}
357362

358-
br->dev->features = features;
363+
done:
364+
br->dev->features = netdev_fix_features(features, NULL);
359365
}
360366

361367
/* called with RTNL */

net/core/dev.c

Lines changed: 71 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3947,6 +3947,46 @@ static void netdev_init_queue_locks(struct net_device *dev)
39473947
__netdev_init_queue_locks_one(dev, &dev->rx_queue, NULL);
39483948
}
39493949

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+
39503990
/**
39513991
* register_netdevice - register a network device
39523992
* @dev: device to register
@@ -4032,36 +4072,7 @@ int register_netdevice(struct net_device *dev)
40324072
dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM);
40334073
}
40344074

4035-
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-
}
4075+
dev->features = netdev_fix_features(dev->features, dev->name);
40654076

40664077
/* Enable software GSO if SG is supported. */
40674078
if (dev->features & NETIF_F_SG)
@@ -4700,49 +4711,45 @@ static int __init netdev_dma_register(void) { return -ENODEV; }
47004711
#endif /* CONFIG_NET_DMA */
47014712

47024713
/**
4703-
* netdev_compute_feature - compute conjunction of two feature sets
4704-
* @all: first feature set
4705-
* @one: second feature set
4714+
* netdev_increment_features - increment feature set by one
4715+
* @all: current feature set
4716+
* @one: new feature set
4717+
* @mask: mask feature set
47064718
*
47074719
* Computes a new feature set after adding a device with feature set
4708-
* @one to the master device with current feature set @all. Returns
4709-
* the new feature set.
4720+
* @one to the master device with current feature set @all. Will not
4721+
* enable anything that is off in @mask. Returns the new feature set.
47104722
*/
4711-
int netdev_compute_features(unsigned long all, unsigned long one)
4712-
{
4713-
/* if device needs checksumming, downgrade to hw checksumming */
4714-
if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM))
4715-
all ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
4716-
4717-
/* if device can't do all checksum, downgrade to ipv4/ipv6 */
4718-
if (all & NETIF_F_HW_CSUM && !(one & NETIF_F_HW_CSUM))
4719-
all ^= NETIF_F_HW_CSUM
4720-
| NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
4721-
4722-
if (one & NETIF_F_GSO)
4723-
one |= NETIF_F_GSO_SOFTWARE;
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;
4723+
unsigned long netdev_increment_features(unsigned long all, unsigned long one,
4724+
unsigned long mask)
4725+
{
4726+
/* If device needs checksumming, downgrade to it. */
4727+
if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM))
4728+
all ^= NETIF_F_NO_CSUM | (one & NETIF_F_ALL_CSUM);
4729+
else if (mask & NETIF_F_ALL_CSUM) {
4730+
/* If one device supports v4/v6 checksumming, set for all. */
4731+
if (one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM) &&
4732+
!(all & NETIF_F_GEN_CSUM)) {
4733+
all &= ~NETIF_F_ALL_CSUM;
4734+
all |= one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
4735+
}
47314736

4732-
/* If even one device supports robust GSO, enable it for all. */
4733-
if (one & NETIF_F_GSO_ROBUST)
4734-
all |= NETIF_F_GSO_ROBUST;
4737+
/* If one device supports hw checksumming, set for all. */
4738+
if (one & NETIF_F_GEN_CSUM && !(all & NETIF_F_GEN_CSUM)) {
4739+
all &= ~NETIF_F_ALL_CSUM;
4740+
all |= NETIF_F_HW_CSUM;
4741+
}
4742+
}
47354743

4736-
all &= one | NETIF_F_LLTX;
4744+
one |= NETIF_F_ALL_CSUM;
47374745

4738-
if (!(all & NETIF_F_ALL_CSUM))
4739-
all &= ~NETIF_F_SG;
4740-
if (!(all & NETIF_F_SG))
4741-
all &= ~NETIF_F_GSO_MASK;
4746+
one |= all & NETIF_F_ONE_FOR_ALL;
4747+
all &= one | NETIF_F_LLTX | NETIF_F_GSO;
4748+
all |= one & mask & NETIF_F_ONE_FOR_ALL;
47424749

47434750
return all;
47444751
}
4745-
EXPORT_SYMBOL(netdev_compute_features);
4752+
EXPORT_SYMBOL(netdev_increment_features);
47464753

47474754
static struct hlist_head *netdev_create_hash(void)
47484755
{

0 commit comments

Comments
 (0)