Skip to content

Commit ca25449

Browse files
David Aherndavem330
authored andcommitted
net: Add VRF support to IPv6 stack
As with IPv4 support for VRFs added to IPv6 stack by replacing hardcoded table ids with possibly device specific ones and manipulating the oif in the flowi6. The flow flags are used to skip oif compare in nexthop lookups if the device is enslaved to a VRF via the L3 master device. Signed-off-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 35402e3 commit ca25449

File tree

5 files changed

+63
-14
lines changed

5 files changed

+63
-14
lines changed

net/ipv6/addrconf.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#include <net/ip.h>
8282
#include <net/netlink.h>
8383
#include <net/pkt_sched.h>
84+
#include <net/l3mdev.h>
8485
#include <linux/if_tunnel.h>
8586
#include <linux/rtnetlink.h>
8687
#include <linux/netconf.h>
@@ -2146,7 +2147,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
21462147
unsigned long expires, u32 flags)
21472148
{
21482149
struct fib6_config cfg = {
2149-
.fc_table = RT6_TABLE_PREFIX,
2150+
.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_PREFIX,
21502151
.fc_metric = IP6_RT_PRIO_ADDRCONF,
21512152
.fc_ifindex = dev->ifindex,
21522153
.fc_expires = expires,
@@ -2179,8 +2180,9 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
21792180
struct fib6_node *fn;
21802181
struct rt6_info *rt = NULL;
21812182
struct fib6_table *table;
2183+
u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_PREFIX;
21822184

2183-
table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX);
2185+
table = fib6_get_table(dev_net(dev), tb_id);
21842186
if (!table)
21852187
return NULL;
21862188

@@ -2211,7 +2213,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
22112213
static void addrconf_add_mroute(struct net_device *dev)
22122214
{
22132215
struct fib6_config cfg = {
2214-
.fc_table = RT6_TABLE_LOCAL,
2216+
.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_LOCAL,
22152217
.fc_metric = IP6_RT_PRIO_ADDRCONF,
22162218
.fc_ifindex = dev->ifindex,
22172219
.fc_dst_len = 8,
@@ -3029,6 +3031,10 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
30293031
{
30303032
struct in6_addr addr;
30313033

3034+
/* no link local addresses on L3 master devices */
3035+
if (netif_is_l3_master(idev->dev))
3036+
return;
3037+
30323038
ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);
30333039

30343040
if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {

net/ipv6/icmp.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#include <net/xfrm.h>
6969
#include <net/inet_common.h>
7070
#include <net/dsfield.h>
71+
#include <net/l3mdev.h>
7172

7273
#include <asm/uaccess.h>
7374

@@ -496,6 +497,9 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
496497
else if (!fl6.flowi6_oif)
497498
fl6.flowi6_oif = np->ucast_oif;
498499

500+
if (!fl6.flowi6_oif)
501+
fl6.flowi6_oif = l3mdev_master_ifindex(skb->dev);
502+
499503
dst = icmpv6_route_lookup(net, skb, sk, &fl6);
500504
if (IS_ERR(dst))
501505
goto out;
@@ -575,7 +579,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
575579
fl6.daddr = ipv6_hdr(skb)->saddr;
576580
if (saddr)
577581
fl6.saddr = *saddr;
578-
fl6.flowi6_oif = skb->dev->ifindex;
582+
fl6.flowi6_oif = l3mdev_fib_oif(skb->dev);
579583
fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
580584
fl6.flowi6_mark = mark;
581585
security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));

net/ipv6/ip6_output.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include <net/xfrm.h>
5656
#include <net/checksum.h>
5757
#include <linux/mroute6.h>
58+
#include <net/l3mdev.h>
5859

5960
static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
6061
{
@@ -885,7 +886,8 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
885886
#ifdef CONFIG_IPV6_SUBTREES
886887
ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) ||
887888
#endif
888-
(fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex)) {
889+
(!(fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF) &&
890+
(fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex))) {
889891
dst_release(dst);
890892
dst = NULL;
891893
}
@@ -1037,7 +1039,7 @@ struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
10371039
if (final_dst)
10381040
fl6->daddr = *final_dst;
10391041
if (!fl6->flowi6_oif)
1040-
fl6->flowi6_oif = dst->dev->ifindex;
1042+
fl6->flowi6_oif = l3mdev_fib_oif(dst->dev);
10411043

10421044
return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
10431045
}

net/ipv6/ndisc.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include <net/flow.h>
6868
#include <net/ip6_checksum.h>
6969
#include <net/inet_common.h>
70+
#include <net/l3mdev.h>
7071
#include <linux/proc_fs.h>
7172

7273
#include <linux/netfilter.h>
@@ -442,8 +443,11 @@ static void ndisc_send_skb(struct sk_buff *skb,
442443

443444
if (!dst) {
444445
struct flowi6 fl6;
446+
int oif = l3mdev_fib_oif(skb->dev);
445447

446-
icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
448+
icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif);
449+
if (oif != skb->dev->ifindex)
450+
fl6.flowi6_flags |= FLOWI_FLAG_L3MDEV_SRC;
447451
dst = icmp6_dst_alloc(skb->dev, &fl6);
448452
if (IS_ERR(dst)) {
449453
kfree_skb(skb);
@@ -767,7 +771,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
767771

768772
ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
769773
if (ifp) {
770-
774+
have_ifp:
771775
if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
772776
if (dad) {
773777
/*
@@ -793,6 +797,18 @@ static void ndisc_recv_ns(struct sk_buff *skb)
793797
} else {
794798
struct net *net = dev_net(dev);
795799

800+
/* perhaps an address on the master device */
801+
if (netif_is_l3_slave(dev)) {
802+
struct net_device *mdev;
803+
804+
mdev = netdev_master_upper_dev_get_rcu(dev);
805+
if (mdev) {
806+
ifp = ipv6_get_ifaddr(net, &msg->target, mdev, 1);
807+
if (ifp)
808+
goto have_ifp;
809+
}
810+
}
811+
796812
idev = in6_dev_get(dev);
797813
if (!idev) {
798814
/* XXX: count this drop? */
@@ -1484,6 +1500,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
14841500
struct flowi6 fl6;
14851501
int rd_len;
14861502
u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
1503+
int oif = l3mdev_fib_oif(dev);
14871504
bool ret;
14881505

14891506
if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
@@ -1500,7 +1517,10 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
15001517
}
15011518

15021519
icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
1503-
&saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
1520+
&saddr_buf, &ipv6_hdr(skb)->saddr, oif);
1521+
1522+
if (oif != skb->dev->ifindex)
1523+
fl6.flowi6_flags |= FLOWI_FLAG_L3MDEV_SRC;
15041524

15051525
dst = ip6_route_output(net, NULL, &fl6);
15061526
if (dst->error) {

net/ipv6/route.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#include <net/nexthop.h>
6262
#include <net/lwtunnel.h>
6363
#include <net/ip_tunnels.h>
64+
#include <net/l3mdev.h>
6465

6566
#include <asm/uaccess.h>
6667

@@ -1044,6 +1045,9 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
10441045
fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
10451046
saved_fn = fn;
10461047

1048+
if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1049+
oif = 0;
1050+
10471051
redo_rt6_select:
10481052
rt = rt6_select(fn, oif, strict);
10491053
if (rt->rt6i_nsiblings)
@@ -1141,7 +1145,7 @@ void ip6_route_input(struct sk_buff *skb)
11411145
int flags = RT6_LOOKUP_F_HAS_SADDR;
11421146
struct ip_tunnel_info *tun_info;
11431147
struct flowi6 fl6 = {
1144-
.flowi6_iif = skb->dev->ifindex,
1148+
.flowi6_iif = l3mdev_fib_oif(skb->dev),
11451149
.daddr = iph->daddr,
11461150
.saddr = iph->saddr,
11471151
.flowlabel = ip6_flowinfo(iph),
@@ -1165,8 +1169,13 @@ static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table
11651169
struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
11661170
struct flowi6 *fl6)
11671171
{
1172+
struct dst_entry *dst;
11681173
int flags = 0;
11691174

1175+
dst = l3mdev_rt6_dst_by_oif(net, fl6);
1176+
if (dst)
1177+
return dst;
1178+
11701179
fl6->flowi6_iif = LOOPBACK_IFINDEX;
11711180

11721181
if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
@@ -2263,7 +2272,6 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
22632272
unsigned int pref)
22642273
{
22652274
struct fib6_config cfg = {
2266-
.fc_table = RT6_TABLE_INFO,
22672275
.fc_metric = IP6_RT_PRIO_USER,
22682276
.fc_ifindex = ifindex,
22692277
.fc_dst_len = prefixlen,
@@ -2274,6 +2282,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
22742282
.fc_nlinfo.nl_net = net,
22752283
};
22762284

2285+
cfg.fc_table = l3mdev_fib_table_by_index(net, ifindex) ? : RT6_TABLE_INFO;
22772286
cfg.fc_dst = *prefix;
22782287
cfg.fc_gateway = *gwaddr;
22792288

@@ -2314,7 +2323,7 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
23142323
unsigned int pref)
23152324
{
23162325
struct fib6_config cfg = {
2317-
.fc_table = RT6_TABLE_DFLT,
2326+
.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
23182327
.fc_metric = IP6_RT_PRIO_USER,
23192328
.fc_ifindex = dev->ifindex,
23202329
.fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
@@ -2361,7 +2370,8 @@ static void rtmsg_to_fib6_config(struct net *net,
23612370
{
23622371
memset(cfg, 0, sizeof(*cfg));
23632372

2364-
cfg->fc_table = RT6_TABLE_MAIN;
2373+
cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
2374+
: RT6_TABLE_MAIN;
23652375
cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
23662376
cfg->fc_metric = rtmsg->rtmsg_metric;
23672377
cfg->fc_expires = rtmsg->rtmsg_info;
@@ -2470,6 +2480,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
24702480
const struct in6_addr *addr,
24712481
bool anycast)
24722482
{
2483+
u32 tb_id;
24732484
struct net *net = dev_net(idev->dev);
24742485
struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
24752486
DST_NOCOUNT);
@@ -2492,7 +2503,8 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
24922503
rt->rt6i_gateway = *addr;
24932504
rt->rt6i_dst.addr = *addr;
24942505
rt->rt6i_dst.plen = 128;
2495-
rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
2506+
tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
2507+
rt->rt6i_table = fib6_get_table(net, tb_id);
24962508
rt->dst.flags |= DST_NOCACHE;
24972509

24982510
atomic_set(&rt->dst.__refcnt, 1);
@@ -3254,6 +3266,11 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
32543266
} else {
32553267
fl6.flowi6_oif = oif;
32563268

3269+
if (netif_index_is_l3_master(net, oif)) {
3270+
fl6.flowi6_flags = FLOWI_FLAG_L3MDEV_SRC |
3271+
FLOWI_FLAG_SKIP_NH_OIF;
3272+
}
3273+
32573274
rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
32583275
}
32593276

0 commit comments

Comments
 (0)