ip_tunnel: allow to inherit from VLAN encapsulated IP
authorMatthias May <matthias.may@westermo.com>
Mon, 11 Jul 2022 09:17:19 +0000 (11:17 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 13 Jul 2022 11:10:21 +0000 (12:10 +0100)
The current code allows to inherit the TOS, TTL, DF from the payload
when skb->protocol is ETH_P_IP or ETH_P_IPV6.
However when the payload is VLAN encapsulated (e.g because the tunnel
is of type GRETAP), then this inheriting does not work, because the
visible skb->protocol is of type ETH_P_8021Q or ETH_P_8021AD.

Instead of skb->protocol, use skb_protocol().

Signed-off-by: Matthias May <matthias.may@westermo.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ip_tunnel.c

index 4688f00a454ce71434c73f15f884fb6fe4c5df3a..e65e948cab9f2a598cac79406f2b8e0ab9c79aba 100644 (file)
@@ -641,6 +641,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        const struct iphdr *inner_iph;
        unsigned int max_headroom;      /* The extra header space needed */
        struct rtable *rt = NULL;               /* Route to the other host */
+       __be16 payload_protocol;
        bool use_cache = false;
        struct flowi4 fl4;
        bool md = false;
@@ -651,6 +652,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
 
        inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
        connected = (tunnel->parms.iph.daddr != 0);
+       payload_protocol = skb_protocol(skb, true);
 
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 
@@ -670,13 +672,12 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                        dst = tun_info->key.u.ipv4.dst;
                        md = true;
                        connected = true;
-               }
-               else if (skb->protocol == htons(ETH_P_IP)) {
+               } else if (payload_protocol == htons(ETH_P_IP)) {
                        rt = skb_rtable(skb);
                        dst = rt_nexthop(rt, inner_iph->daddr);
                }
 #if IS_ENABLED(CONFIG_IPV6)
-               else if (skb->protocol == htons(ETH_P_IPV6)) {
+               else if (payload_protocol == htons(ETH_P_IPV6)) {
                        const struct in6_addr *addr6;
                        struct neighbour *neigh;
                        bool do_tx_error_icmp;
@@ -716,10 +717,10 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        tos = tnl_params->tos;
        if (tos & 0x1) {
                tos &= ~0x1;
-               if (skb->protocol == htons(ETH_P_IP)) {
+               if (payload_protocol == htons(ETH_P_IP)) {
                        tos = inner_iph->tos;
                        connected = false;
-               } else if (skb->protocol == htons(ETH_P_IPV6)) {
+               } else if (payload_protocol == htons(ETH_P_IPV6)) {
                        tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
                        connected = false;
                }
@@ -765,7 +766,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        }
 
        df = tnl_params->frag_off;
-       if (skb->protocol == htons(ETH_P_IP) && !tunnel->ignore_df)
+       if (payload_protocol == htons(ETH_P_IP) && !tunnel->ignore_df)
                df |= (inner_iph->frag_off & htons(IP_DF));
 
        if (tnl_update_pmtu(dev, skb, rt, df, inner_iph, 0, 0, false)) {
@@ -786,10 +787,10 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
        ttl = tnl_params->ttl;
        if (ttl == 0) {
-               if (skb->protocol == htons(ETH_P_IP))
+               if (payload_protocol == htons(ETH_P_IP))
                        ttl = inner_iph->ttl;
 #if IS_ENABLED(CONFIG_IPV6)
-               else if (skb->protocol == htons(ETH_P_IPV6))
+               else if (payload_protocol == htons(ETH_P_IPV6))
                        ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit;
 #endif
                else