Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

e1000e: Fix TSO with non-accelerated vlans

This device claims TSO support for vlans. It also allows a
user to control vlan acceleration offloading. As such, it is
possible to turn off vlan acceleration and configure a vlan
which will continue to support TSO.

In such situation the packet passed down the the device will contain
a vlan header and skb->protocol will be set to ETH_P_8021Q.
The device assumes that skb->protocol contains network protocol
value and uses that value to set up TSO information. This results
in corrupted frames sent on the wire. Corruptions include
incorrect IP total length and invalid IP checksum.

This patch extract the protocol value correctly and corrects TSO
for non-accelerated traffic.

CC: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
CC: Jesse Brandeburg <jesse.brandeburg@intel.com>
CC: Bruce Allan <bruce.w.allan@intel.com>
CC: Carolyn Wyborny <carolyn.wyborny@intel.com>
CC: Don Skidmore <donald.c.skidmore@intel.com>
CC: Greg Rose <gregory.v.rose@intel.com>
CC: Alex Duyck <alexander.h.duyck@intel.com>
CC: John Ronciak <john.ronciak@intel.com>
CC: Mitch Williams <mitch.a.williams@intel.com>
CC: Linux NICS <linux.nics@intel.com>
CC: e1000-devel@lists.sourceforge.net
Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vlad Yasevich and committed by
David S. Miller
47ccd1ed 2b7890e7

+9 -12
+9 -12
drivers/net/ethernet/intel/e1000e/netdev.c
··· 5164 5164 #define E1000_TX_FLAGS_VLAN_MASK 0xffff0000 5165 5165 #define E1000_TX_FLAGS_VLAN_SHIFT 16 5166 5166 5167 - static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb) 5167 + static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb, 5168 + __be16 protocol) 5168 5169 { 5169 5170 struct e1000_context_desc *context_desc; 5170 5171 struct e1000_buffer *buffer_info; ··· 5184 5183 5185 5184 hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); 5186 5185 mss = skb_shinfo(skb)->gso_size; 5187 - if (skb->protocol == htons(ETH_P_IP)) { 5186 + if (protocol == htons(ETH_P_IP)) { 5188 5187 struct iphdr *iph = ip_hdr(skb); 5189 5188 iph->tot_len = 0; 5190 5189 iph->check = 0; ··· 5232 5231 return 1; 5233 5232 } 5234 5233 5235 - static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb) 5234 + static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb, 5235 + __be16 protocol) 5236 5236 { 5237 5237 struct e1000_adapter *adapter = tx_ring->adapter; 5238 5238 struct e1000_context_desc *context_desc; ··· 5241 5239 unsigned int i; 5242 5240 u8 css; 5243 5241 u32 cmd_len = E1000_TXD_CMD_DEXT; 5244 - __be16 protocol; 5245 5242 5246 5243 if (skb->ip_summed != CHECKSUM_PARTIAL) 5247 5244 return false; 5248 - 5249 - if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) 5250 - protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; 5251 - else 5252 - protocol = skb->protocol; 5253 5245 5254 5246 switch (protocol) { 5255 5247 case cpu_to_be16(ETH_P_IP): ··· 5542 5546 int count = 0; 5543 5547 int tso; 5544 5548 unsigned int f; 5549 + __be16 protocol = vlan_get_protocol(skb); 5545 5550 5546 5551 if (test_bit(__E1000_DOWN, &adapter->state)) { 5547 5552 dev_kfree_skb_any(skb); ··· 5617 5620 5618 5621 first = tx_ring->next_to_use; 5619 5622 5620 - tso = e1000_tso(tx_ring, skb); 5623 + tso = e1000_tso(tx_ring, skb, protocol); 5621 5624 if (tso < 0) { 5622 5625 dev_kfree_skb_any(skb); 5623 5626 return NETDEV_TX_OK; ··· 5625 5628 5626 5629 if (tso) 5627 5630 tx_flags |= E1000_TX_FLAGS_TSO; 5628 - else if (e1000_tx_csum(tx_ring, skb)) 5631 + else if (e1000_tx_csum(tx_ring, skb, protocol)) 5629 5632 tx_flags |= E1000_TX_FLAGS_CSUM; 5630 5633 5631 5634 /* Old method was to assume IPv4 packet by default if TSO was enabled. 5632 5635 * 82571 hardware supports TSO capabilities for IPv6 as well... 5633 5636 * no longer assume, we must. 5634 5637 */ 5635 - if (skb->protocol == htons(ETH_P_IP)) 5638 + if (protocol == htons(ETH_P_IP)) 5636 5639 tx_flags |= E1000_TX_FLAGS_IPV4; 5637 5640 5638 5641 if (unlikely(skb->no_fcs))