ipmr: vrf: Find VIFs using the actual device
authorThomas Winter <Thomas.Winter@alliedtelesis.co.nz>
Mon, 15 May 2017 22:14:44 +0000 (10:14 +1200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 May 2017 16:52:17 +0000 (12:52 -0400)
The skb->dev that is passed into ip_mr_input is
the loX device for VRFs. When we lookup a vif
for this dev, none is found as we do not create
vifs for loopbacks. Instead lookup a vif for the
actual device that the packet was received on,
eg the vlan.

Signed-off-by: Thomas Winter <Thomas.Winter@alliedtelesis.co.nz>
cc: David Ahern <dsa@cumulusnetworks.com>
cc: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
cc: roopa <roopa@cumulusnetworks.com>
Acked-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ipmr.c

index 3a02d52ed50ec54ce3f9f3eb07dc9f4133535a80..551de4d023a8edbf74835b43cb32d9173eedae36 100644 (file)
@@ -1980,6 +1980,20 @@ int ip_mr_input(struct sk_buff *skb)
        struct net *net = dev_net(skb->dev);
        int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
        struct mr_table *mrt;
+       struct net_device *dev;
+
+       /* skb->dev passed in is the loX master dev for vrfs.
+        * As there are no vifs associated with loopback devices,
+        * get the proper interface that does have a vif associated with it.
+        */
+       dev = skb->dev;
+       if (netif_is_l3_master(skb->dev)) {
+               dev = dev_get_by_index_rcu(net, IPCB(skb)->iif);
+               if (!dev) {
+                       kfree_skb(skb);
+                       return -ENODEV;
+               }
+       }
 
        /* Packet is looped back after forward, it should not be
         * forwarded second time, but still can be delivered locally.
@@ -2017,7 +2031,7 @@ int ip_mr_input(struct sk_buff *skb)
        /* already under rcu_read_lock() */
        cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
        if (!cache) {
-               int vif = ipmr_find_vif(mrt, skb->dev);
+               int vif = ipmr_find_vif(mrt, dev);
 
                if (vif >= 0)
                        cache = ipmr_cache_find_any(mrt, ip_hdr(skb)->daddr,
@@ -2037,7 +2051,7 @@ int ip_mr_input(struct sk_buff *skb)
                }
 
                read_lock(&mrt_lock);
-               vif = ipmr_find_vif(mrt, skb->dev);
+               vif = ipmr_find_vif(mrt, dev);
                if (vif >= 0) {
                        int err2 = ipmr_cache_unresolved(mrt, vif, skb);
                        read_unlock(&mrt_lock);