| From foo@baz Wed May 31 09:13:34 JST 2017 |
| From: Vlad Yasevich <vyasevich@gmail.com> |
| Date: Tue, 23 May 2017 13:38:41 -0400 |
| Subject: vlan: Fix tcp checksum offloads in Q-in-Q vlans |
| |
| From: Vlad Yasevich <vyasevich@gmail.com> |
| |
| |
| [ Upstream commit 35d2f80b07bbe03fb358afb0bdeff7437a7d67ff ] |
| |
| It appears that TCP checksum offloading has been broken for |
| Q-in-Q vlans. The behavior was execerbated by the |
| series |
| commit afb0bc972b52 ("Merge branch 'stacked_vlan_tso'") |
| that that enabled accleleration features on stacked vlans. |
| |
| However, event without that series, it is possible to trigger |
| this issue. It just requires a lot more specialized configuration. |
| |
| The root cause is the interaction between how |
| netdev_intersect_features() works, the features actually set on |
| the vlan devices and HW having the ability to run checksum with |
| longer headers. |
| |
| The issue starts when netdev_interesect_features() replaces |
| NETIF_F_HW_CSUM with a combination of NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM, |
| if the HW advertises IP|IPV6 specific checksums. This happens |
| for tagged and multi-tagged packets. However, HW that enables |
| IP|IPV6 checksum offloading doesn't gurantee that packets with |
| arbitrarily long headers can be checksummed. |
| |
| This patch disables IP|IPV6 checksums on the packet for multi-tagged |
| packets. |
| |
| CC: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> |
| CC: Michal Kubecek <mkubecek@suse.cz> |
| Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com> |
| Acked-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/linux/if_vlan.h | 18 ++++++++++-------- |
| 1 file changed, 10 insertions(+), 8 deletions(-) |
| |
| --- a/include/linux/if_vlan.h |
| +++ b/include/linux/if_vlan.h |
| @@ -630,14 +630,16 @@ static inline bool skb_vlan_tagged_multi |
| static inline netdev_features_t vlan_features_check(const struct sk_buff *skb, |
| netdev_features_t features) |
| { |
| - if (skb_vlan_tagged_multi(skb)) |
| - features = netdev_intersect_features(features, |
| - NETIF_F_SG | |
| - NETIF_F_HIGHDMA | |
| - NETIF_F_FRAGLIST | |
| - NETIF_F_HW_CSUM | |
| - NETIF_F_HW_VLAN_CTAG_TX | |
| - NETIF_F_HW_VLAN_STAG_TX); |
| + if (skb_vlan_tagged_multi(skb)) { |
| + /* In the case of multi-tagged packets, use a direct mask |
| + * instead of using netdev_interesect_features(), to make |
| + * sure that only devices supporting NETIF_F_HW_CSUM will |
| + * have checksum offloading support. |
| + */ |
| + features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | |
| + NETIF_F_FRAGLIST | NETIF_F_HW_VLAN_CTAG_TX | |
| + NETIF_F_HW_VLAN_STAG_TX; |
| + } |
| |
| return features; |
| } |