vti[6]: fix packet tx through bpf_redirect() in XinY cases
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Tue, 4 Feb 2020 16:00:27 +0000 (17:00 +0100)
committerSteffen Klassert <steffen.klassert@secunet.com>
Thu, 6 Feb 2020 12:27:30 +0000 (13:27 +0100)
I forgot the 4in6/6in4 cases in my previous patch. Let's fix them.

Fixes: 95224166a903 ("vti[6]: fix packet tx through bpf_redirect()")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/ipv4/Kconfig
net/ipv4/ip_vti.c
net/ipv6/ip6_vti.c

index f96bd48..6490b84 100644 (file)
@@ -303,6 +303,7 @@ config SYN_COOKIES
 
 config NET_IPVTI
        tristate "Virtual (secure) IP: tunneling"
+       depends on IPV6 || IPV6=n
        select INET_TUNNEL
        select NET_IP_TUNNEL
        select XFRM
index 37cddd1..1b4e6f2 100644 (file)
@@ -187,17 +187,39 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
        int mtu;
 
        if (!dst) {
-               struct rtable *rt;
-
-               fl->u.ip4.flowi4_oif = dev->ifindex;
-               fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
-               rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
-               if (IS_ERR(rt)) {
+               switch (skb->protocol) {
+               case htons(ETH_P_IP): {
+                       struct rtable *rt;
+
+                       fl->u.ip4.flowi4_oif = dev->ifindex;
+                       fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
+                       rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
+                       if (IS_ERR(rt)) {
+                               dev->stats.tx_carrier_errors++;
+                               goto tx_error_icmp;
+                       }
+                       dst = &rt->dst;
+                       skb_dst_set(skb, dst);
+                       break;
+               }
+#if IS_ENABLED(CONFIG_IPV6)
+               case htons(ETH_P_IPV6):
+                       fl->u.ip6.flowi6_oif = dev->ifindex;
+                       fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
+                       dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
+                       if (dst->error) {
+                               dst_release(dst);
+                               dst = NULL;
+                               dev->stats.tx_carrier_errors++;
+                               goto tx_error_icmp;
+                       }
+                       skb_dst_set(skb, dst);
+                       break;
+#endif
+               default:
                        dev->stats.tx_carrier_errors++;
                        goto tx_error_icmp;
                }
-               dst = &rt->dst;
-               skb_dst_set(skb, dst);
        }
 
        dst_hold(dst);
index 524006a..56e642e 100644 (file)
@@ -450,15 +450,33 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
        int mtu;
 
        if (!dst) {
-               fl->u.ip6.flowi6_oif = dev->ifindex;
-               fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
-               dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
-               if (dst->error) {
-                       dst_release(dst);
-                       dst = NULL;
+               switch (skb->protocol) {
+               case htons(ETH_P_IP): {
+                       struct rtable *rt;
+
+                       fl->u.ip4.flowi4_oif = dev->ifindex;
+                       fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
+                       rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
+                       if (IS_ERR(rt))
+                               goto tx_err_link_failure;
+                       dst = &rt->dst;
+                       skb_dst_set(skb, dst);
+                       break;
+               }
+               case htons(ETH_P_IPV6):
+                       fl->u.ip6.flowi6_oif = dev->ifindex;
+                       fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
+                       dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
+                       if (dst->error) {
+                               dst_release(dst);
+                               dst = NULL;
+                               goto tx_err_link_failure;
+                       }
+                       skb_dst_set(skb, dst);
+                       break;
+               default:
                        goto tx_err_link_failure;
                }
-               skb_dst_set(skb, dst);
        }
 
        dst_hold(dst);