]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
fm10k: fix incorrect IPv6 extended header checksum
authorJacob Keller <jacob.e.keller@intel.com>
Thu, 7 Apr 2016 15:52:53 +0000 (08:52 -0700)
committerChuck Anderson <chuck.anderson@oracle.com>
Sun, 26 Feb 2017 06:04:12 +0000 (22:04 -0800)
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: Mark Rustad <mark.d.rustad@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Krishneil Singh <Krishneil.k.singh@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Orabug: 25394529
(cherry picked from commit dc1b4c2b88b976a7882922e55666b20e28477c57)
Signed-off-by: Jack Vogel <jack.vogel@oracle.com>
drivers/net/ethernet/intel/fm10k/fm10k_main.c

index 2d700d7a9dbf73d446c6b5c018197e8d5ec5fe72..b9d47499f3e21b039021d3a491020e7cb8224de9 100644 (file)
@@ -835,6 +835,8 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring,
                struct ipv6hdr *ipv6;
                u8 *raw;
        } network_hdr;
+       u8 *transport_hdr;
+       __be16 frag_off;
        __be16 protocol;
        u8 l4_hdr = 0;
 
@@ -852,9 +854,11 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring,
                        goto no_csum;
                }
                network_hdr.raw = skb_inner_network_header(skb);
+               transport_hdr = skb_inner_transport_header(skb);
        } else {
                protocol = vlan_get_protocol(skb);
                network_hdr.raw = skb_network_header(skb);
+               transport_hdr = skb_transport_header(skb);
        }
 
        switch (protocol) {
@@ -863,15 +867,17 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring,
                break;
        case htons(ETH_P_IPV6):
                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;
        default:
-               if (unlikely(net_ratelimit())) {
-                       dev_warn(tx_ring->dev,
-                                "partial checksum but ip version=%x!\n",
-                                protocol);
-               }
-               tx_ring->tx_stats.csum_err++;
-               goto no_csum;
+               break;
        }
 
        switch (l4_hdr) {
@@ -884,9 +890,10 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring,
        default:
                if (unlikely(net_ratelimit())) {
                        dev_warn(tx_ring->dev,
-                                "partial checksum but l4 proto=%x!\n",
-                                l4_hdr);
+                                "partial checksum, version=%d l4 proto=%x\n",
+                                protocol, l4_hdr);
                }
+               skb_checksum_help(skb);
                tx_ring->tx_stats.csum_err++;
                goto no_csum;
        }