net: Use VRF device index for lookups on TX
authorDavid Ahern <dsa@cumulusnetworks.com>
Thu, 13 Aug 2015 20:59:02 +0000 (14:59 -0600)
committerDavid S. Miller <davem@davemloft.net>
Fri, 14 Aug 2015 05:43:20 +0000 (22:43 -0700)
As with ingress use the index of VRF master device for route lookups on
egress. However, the oif should only be used to direct the lookups to a
specific table. Routes in the table are not based on the VRF device but
rather interfaces that are part of the VRF so do not consider the oif for
lookups within the table. The FLOWI_FLAG_VRFSRC is used to control this
latter part.

Signed-off-by: Shrijeet Mukherjee <shm@cumulusnetworks.com>
Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/flow.h
include/net/route.h
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/route.c

index 3098ae3..f305588 100644 (file)
@@ -33,6 +33,7 @@ struct flowi_common {
        __u8    flowic_flags;
 #define FLOWI_FLAG_ANYSRC              0x01
 #define FLOWI_FLAG_KNOWN_NH            0x02
+#define FLOWI_FLAG_VRFSRC              0x04
        __u32   flowic_secid;
        struct flowi_tunnel flowic_tun_key;
 };
index 2d45f41..94189d4 100644 (file)
@@ -251,6 +251,9 @@ static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32
        if (inet_sk(sk)->transparent)
                flow_flags |= FLOWI_FLAG_ANYSRC;
 
+       if (netif_index_is_vrf(sock_net(sk), oif))
+               flow_flags |= FLOWI_FLAG_VRFSRC;
+
        flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE,
                           protocol, flow_flags, dst, src, dport, sport);
 }
index 37c4bb8..1243c79 100644 (file)
@@ -1423,8 +1423,11 @@ found:
                            nh->nh_flags & RTNH_F_LINKDOWN &&
                            !(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
                                continue;
-                       if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
-                               continue;
+                       if (!(flp->flowi4_flags & FLOWI_FLAG_VRFSRC)) {
+                               if (flp->flowi4_oif &&
+                                   flp->flowi4_oif != nh->nh_oif)
+                                       continue;
+                       }
 
                        if (!(fib_flags & FIB_LOOKUP_NOREF))
                                atomic_inc(&fi->fib_clntref);
index c0556f1..1164fc4 100644 (file)
@@ -96,6 +96,7 @@
 #include <net/xfrm.h>
 #include <net/inet_common.h>
 #include <net/ip_fib.h>
+#include <net/vrf.h>
 
 /*
  *     Build xmit assembly blocks
@@ -425,6 +426,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
        fl4.flowi4_mark = mark;
        fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
        fl4.flowi4_proto = IPPROTO_ICMP;
+       fl4.flowi4_oif = vrf_master_ifindex_rcu(skb->dev) ? : skb->dev->ifindex;
        security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
        rt = ip_route_output_key(net, &fl4);
        if (IS_ERR(rt))
@@ -458,6 +460,8 @@ static struct rtable *icmp_route_lookup(struct net *net,
        fl4->flowi4_proto = IPPROTO_ICMP;
        fl4->fl4_icmp_type = type;
        fl4->fl4_icmp_code = code;
+       fl4->flowi4_oif = vrf_master_ifindex_rcu(skb_in->dev) ? : skb_in->dev->ifindex;
+
        security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4));
        rt = __ip_route_output_key(net, fl4);
        if (IS_ERR(rt))
index c26ff1f..2c89d29 100644 (file)
@@ -2131,6 +2131,11 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
                                fl4->saddr = inet_select_addr(dev_out, 0,
                                                              RT_SCOPE_HOST);
                }
+               if (netif_is_vrf(dev_out) &&
+                   !(fl4->flowi4_flags & FLOWI_FLAG_VRFSRC)) {
+                       rth = vrf_dev_get_rth(dev_out);
+                       goto out;
+               }
        }
 
        if (!fl4->daddr) {