Commit dc1b4c2b authored by Jacob Keller's avatar Jacob Keller Committed by Jeff Kirsher

fm10k: fix incorrect IPv6 extended header checksum

Check for and handle IPv6 extended headers so that Tx checksum offload
can be done. Also use skb_checksum_help for unexpected cases. This was
originally discovered in ixgbe.
Reported-by: default avatarMark Rustad <mark.d.rustad@intel.com>
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Tested-by: default avatarKrishneil Singh <Krishneil.k.singh@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 86641094
...@@ -820,6 +820,8 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring, ...@@ -820,6 +820,8 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring,
struct ipv6hdr *ipv6; struct ipv6hdr *ipv6;
u8 *raw; u8 *raw;
} network_hdr; } network_hdr;
u8 *transport_hdr;
__be16 frag_off;
__be16 protocol; __be16 protocol;
u8 l4_hdr = 0; u8 l4_hdr = 0;
...@@ -837,9 +839,11 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring, ...@@ -837,9 +839,11 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring,
goto no_csum; goto no_csum;
} }
network_hdr.raw = skb_inner_network_header(skb); network_hdr.raw = skb_inner_network_header(skb);
transport_hdr = skb_inner_transport_header(skb);
} else { } else {
protocol = vlan_get_protocol(skb); protocol = vlan_get_protocol(skb);
network_hdr.raw = skb_network_header(skb); network_hdr.raw = skb_network_header(skb);
transport_hdr = skb_transport_header(skb);
} }
switch (protocol) { switch (protocol) {
...@@ -848,15 +852,17 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring, ...@@ -848,15 +852,17 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring,
break; break;
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
l4_hdr = network_hdr.ipv6->nexthdr; l4_hdr = network_hdr.ipv6->nexthdr;
if (likely((transport_hdr - network_hdr.raw) ==
sizeof(struct ipv6hdr)))
break;
ipv6_skip_exthdr(skb, network_hdr.raw - skb->data +
sizeof(struct ipv6hdr),
&l4_hdr, &frag_off);
if (unlikely(frag_off))
l4_hdr = NEXTHDR_FRAGMENT;
break; break;
default: default:
if (unlikely(net_ratelimit())) { break;
dev_warn(tx_ring->dev,
"partial checksum but ip version=%x!\n",
protocol);
}
tx_ring->tx_stats.csum_err++;
goto no_csum;
} }
switch (l4_hdr) { switch (l4_hdr) {
...@@ -869,9 +875,10 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring, ...@@ -869,9 +875,10 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring,
default: default:
if (unlikely(net_ratelimit())) { if (unlikely(net_ratelimit())) {
dev_warn(tx_ring->dev, dev_warn(tx_ring->dev,
"partial checksum but l4 proto=%x!\n", "partial checksum, version=%d l4 proto=%x\n",
l4_hdr); protocol, l4_hdr);
} }
skb_checksum_help(skb);
tx_ring->tx_stats.csum_err++; tx_ring->tx_stats.csum_err++;
goto no_csum; goto no_csum;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment