While parsing the header of a Receive Side Coalesced (RSC) packet, check
if a VLAN tag is present and adjust the header parsing accordingly.
Otherwise, Rx TCP traffic is completely broken for any VLAN interface
whose underlying interface has RSC (rx-gro-hw) enabled.

We only need to worry about one VLAN header since Rx packets with
multiple VLAN headers are not candidates for RSC.

Fixes: 3a8845af66edb ("idpf: add RX splitq napi poll support")
Signed-off-by: Joshua Hay <[email protected]>
Reviewed-by: Emil Tantilov <[email protected]>
---
 drivers/net/ethernet/intel/idpf/idpf_txrx.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c 
b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index c724d429a7aa..70553f64f770 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -3299,6 +3299,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct 
sk_buff *skb,
                       struct libeth_rx_pt decoded)
 {
        u16 rsc_segments, rsc_seg_len;
+       u16 l3_start = 0;
        bool ipv4, ipv6;
        int len;
 
@@ -3321,7 +3322,10 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct 
sk_buff *skb,
        NAPI_GRO_CB(skb)->count = rsc_segments;
        skb_shinfo(skb)->gso_size = rsc_seg_len;
 
-       skb_reset_network_header(skb);
+       if (unlikely(eth_type_vlan(skb->protocol)))
+               l3_start = VLAN_HLEN;
+
+       skb_set_network_header(skb, l3_start);
 
        if (ipv4) {
                struct iphdr *ipv4h = ip_hdr(skb);
@@ -3329,7 +3333,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct 
sk_buff *skb,
                skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
 
                /* Reset and set transport header offset in skb */
-               skb_set_transport_header(skb, sizeof(struct iphdr));
+               skb_set_transport_header(skb, l3_start + sizeof(struct iphdr));
                len = skb->len - skb_transport_offset(skb);
 
                /* Compute the TCP pseudo header checksum*/
@@ -3339,7 +3343,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct 
sk_buff *skb,
                struct ipv6hdr *ipv6h = ipv6_hdr(skb);
 
                skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
-               skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+               skb_set_transport_header(skb, l3_start + sizeof(struct 
ipv6hdr));
                len = skb->len - skb_transport_offset(skb);
                tcp_hdr(skb)->check =
                        ~tcp_v6_check(len, &ipv6h->saddr, &ipv6h->daddr, 0);
-- 
2.39.2

Reply via email to