net: Fix esp GSO on inter address family tunnels.
authorSteffen Klassert <steffen.klassert@secunet.com>
Mon, 7 Mar 2022 12:11:41 +0000 (13:11 +0100)
committerSteffen Klassert <steffen.klassert@secunet.com>
Mon, 7 Mar 2022 12:14:04 +0000 (13:14 +0100)
The esp tunnel GSO handlers use skb_mac_gso_segment to
push the inner packet to the segmentation handlers.
However, skb_mac_gso_segment takes the Ethernet Protocol
ID from 'skb->protocol' which is wrong for inter address
family tunnels. We fix this by introducing a new
skb_eth_gso_segment function.

This function can be used if it is necessary to pass the
Ethernet Protocol ID directly to the segmentation handler.
First users of this function will be the esp4 and esp6
tunnel segmentation handlers.

Fixes: c35fe4106b92 ("xfrm: Add mode handlers for IPsec on layer 2")
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
include/linux/netdevice.h
net/core/gro.c
net/ipv4/esp4_offload.c
net/ipv6/esp6_offload.c

index 8b5a314db167d5acf470d63863ef98793af1b85d..f53ea7038441805d5d8fc864be14893f6856bfaa 100644 (file)
@@ -4602,6 +4602,8 @@ int skb_csum_hwoffload_help(struct sk_buff *skb,
 
 struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
                                  netdev_features_t features, bool tx_path);
+struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
+                                   netdev_features_t features, __be16 type);
 struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
                                    netdev_features_t features);
 
index a11b286d149593827f1990fb8d06b0295fa72189..b7d2b0dc59a288a34204b23ee313dbd1e7c635c7 100644 (file)
@@ -92,6 +92,31 @@ void dev_remove_offload(struct packet_offload *po)
 }
 EXPORT_SYMBOL(dev_remove_offload);
 
+/**
+ *     skb_eth_gso_segment - segmentation handler for ethernet protocols.
+ *     @skb: buffer to segment
+ *     @features: features for the output path (see dev->features)
+ *     @type: Ethernet Protocol ID
+ */
+struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
+                                   netdev_features_t features, __be16 type)
+{
+       struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
+       struct packet_offload *ptype;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(ptype, &offload_base, list) {
+               if (ptype->type == type && ptype->callbacks.gso_segment) {
+                       segs = ptype->callbacks.gso_segment(skb, features);
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       return segs;
+}
+EXPORT_SYMBOL(skb_eth_gso_segment);
+
 /**
  *     skb_mac_gso_segment - mac layer segmentation handler.
  *     @skb: buffer to segment
index 146d4d54830c88fc21a63bb145d17def8a5b005c..935026f4c807e5f02129dd31190617b3e066ff1d 100644 (file)
@@ -110,8 +110,7 @@ static struct sk_buff *xfrm4_tunnel_gso_segment(struct xfrm_state *x,
                                                struct sk_buff *skb,
                                                netdev_features_t features)
 {
-       __skb_push(skb, skb->mac_len);
-       return skb_mac_gso_segment(skb, features);
+       return skb_eth_gso_segment(skb, features, htons(ETH_P_IP));
 }
 
 static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x,
index e61172d50817ade1db9bd759a1a56eedbbe78359..3a293838a91db4846aee08260ca1ec1e290972e7 100644 (file)
@@ -145,8 +145,7 @@ static struct sk_buff *xfrm6_tunnel_gso_segment(struct xfrm_state *x,
                                                struct sk_buff *skb,
                                                netdev_features_t features)
 {
-       __skb_push(skb, skb->mac_len);
-       return skb_mac_gso_segment(skb, features);
+       return skb_eth_gso_segment(skb, features, htons(ETH_P_IPV6));
 }
 
 static struct sk_buff *xfrm6_transport_gso_segment(struct xfrm_state *x,