mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 00:40:03 +00:00
net: Fix test for VLAN TX checksum offload capability
Selected device feature bits can be propagated to VLAN devices, so we can make use of TX checksum offload and TSO on VLAN-tagged packets. However, if the physical device does not do VLAN tag insertion or generic checksum offload then the test for TX checksum offload in dev_queue_xmit() will see a protocol of htons(ETH_P_8021Q) and yield false. This splits the checksum offload test into two functions: - can_checksum_protocol() tests a given protocol against a feature bitmask - dev_can_checksum() first tests the skb protocol against the device features; if that fails and the protocol is htons(ETH_P_8021Q) then it tests the encapsulated protocol against the effective device features for VLANs Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Acked-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
319fa2a24f
commit
6de329e26c
1 changed files with 26 additions and 8 deletions
|
@ -119,6 +119,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/if_vlan.h>
|
||||
|
||||
#include "net-sysfs.h"
|
||||
|
||||
|
@ -1362,6 +1363,29 @@ void netif_device_attach(struct net_device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL(netif_device_attach);
|
||||
|
||||
static bool can_checksum_protocol(unsigned long features, __be16 protocol)
|
||||
{
|
||||
return ((features & NETIF_F_GEN_CSUM) ||
|
||||
((features & NETIF_F_IP_CSUM) &&
|
||||
protocol == htons(ETH_P_IP)) ||
|
||||
((features & NETIF_F_IPV6_CSUM) &&
|
||||
protocol == htons(ETH_P_IPV6)));
|
||||
}
|
||||
|
||||
static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
if (can_checksum_protocol(dev->features, skb->protocol))
|
||||
return true;
|
||||
|
||||
if (skb->protocol == htons(ETH_P_8021Q)) {
|
||||
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
|
||||
if (can_checksum_protocol(dev->features & dev->vlan_features,
|
||||
veh->h_vlan_encapsulated_proto))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate hardware checksum when packet is to be mangled, and
|
||||
|
@ -1640,14 +1664,8 @@ int dev_queue_xmit(struct sk_buff *skb)
|
|||
if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
skb_set_transport_header(skb, skb->csum_start -
|
||||
skb_headroom(skb));
|
||||
|
||||
if (!(dev->features & NETIF_F_GEN_CSUM) &&
|
||||
!((dev->features & NETIF_F_IP_CSUM) &&
|
||||
skb->protocol == htons(ETH_P_IP)) &&
|
||||
!((dev->features & NETIF_F_IPV6_CSUM) &&
|
||||
skb->protocol == htons(ETH_P_IPV6)))
|
||||
if (skb_checksum_help(skb))
|
||||
goto out_kfree_skb;
|
||||
if (!dev_can_checksum(dev, skb) && skb_checksum_help(skb))
|
||||
goto out_kfree_skb;
|
||||
}
|
||||
|
||||
gso:
|
||||
|
|
Loading…
Reference in a new issue