@@ -1857,7 +1857,8 @@ __u32 dev_vrf(const struct net_device *dev)
static inline
int dev_net_ctx_eq(const struct net_device *dev, struct net_ctx *ctx)
{
- if (net_eq(dev_net(dev), ctx->net))
+ if (net_eq(dev_net(dev), ctx->net) &&
+ vrf_eq(dev_vrf(dev), ctx->vrf))
return 1;
return 0;
@@ -101,7 +101,8 @@ void ib_net_ctx_set(struct inet_bind_bucket *ib, struct net_ctx *ctx)
static inline
int ib_net_ctx_eq(struct inet_bind_bucket *ib, struct net_ctx *ctx)
{
- if (net_eq(ib_net(ib), ctx->net))
+ if (net_eq(ib_net(ib), ctx->net) &&
+ vrf_eq(ib->ib_net_ctx.vrf, ctx->vrf))
return 1;
return 0;
@@ -127,7 +127,8 @@ struct fib_info {
static inline
int fib_net_ctx_eq(const struct fib_info *fi, const struct net_ctx *ctx)
{
- if (net_eq(fi->fib_net_ctx.net, ctx->net))
+ if (net_eq(fi->fib_net_ctx.net, ctx->net) &&
+ vrf_eq(fi->fib_net_ctx.vrf, ctx->vrf))
return 1;
return 0;
@@ -247,7 +247,7 @@ static inline
int fl_net_ctx_eq(struct ip6_flowlabel *fl, struct net_ctx *ctx)
{
#ifdef CONFIG_NET_NS
- return net_eq(fl->fl_net, ctx->net);
+ return net_eq(fl->fl_net, ctx->net) && vrf_eq(fl->fl_vrf, ctx->vrf);
#else
return 1;
#endif
@@ -294,7 +294,8 @@ int neigh_parms_net_ctx_eq(const struct neigh_parms *parms,
const struct net_ctx *net_ctx)
{
#ifdef CONFIG_NET_NS
- if (net_eq(neigh_parms_net(parms), net_ctx->net))
+ if (net_eq(neigh_parms_net(parms), net_ctx->net) &&
+ vrf_eq(neigh_parms_vrf(parms), net_ctx->vrf))
return 1;
return 0;
@@ -330,7 +331,8 @@ int pneigh_net_ctx_eq(const struct pneigh_entry *pneigh,
const struct net_ctx *net_ctx)
{
#ifdef CONFIG_NET_NS
- if (net_eq(pneigh_net(pneigh), net_ctx->net))
+ if (net_eq(pneigh_net(pneigh), net_ctx->net) &&
+ vrf_eq(pneigh->net_ctx.vrf, net_ctx->vrf))
return 1;
return 0;
@@ -215,7 +215,7 @@ int net_eq(const struct net *net1, const struct net *net2)
static inline
int net_ctx_eq(struct net_ctx *ctx1, struct net_ctx *ctx2)
{
- return net_eq(ctx1->net, ctx2->net);
+ return net_eq(ctx1->net, ctx2->net) && vrf_eq(ctx1->vrf, ctx2->vrf);
}
@@ -2205,7 +2205,7 @@ void sock_net_set(struct sock *sk, struct net *net)
static inline
int sock_net_ctx_eq(struct sock *sk, struct net_ctx *ctx)
{
- return net_eq(sock_net(sk), ctx->net);
+ return net_eq(sock_net(sk), ctx->net) && vrf_eq(sk->sk_vrf, ctx->vrf);
}
/*
@@ -688,6 +688,9 @@ struct net_device *__dev_get_by_name_ctx(struct net_ctx *ctx, const char *name)
{
struct net_device *dev = __dev_get_by_name(ctx->net, name);
+ if (dev && !vrf_eq(dev_vrf(dev), ctx->vrf))
+ dev = NULL;
+
return dev;
}
EXPORT_SYMBOL(__dev_get_by_name_ctx);
@@ -771,6 +774,9 @@ struct net_device *__dev_get_by_index_ctx(struct net_ctx *ctx, int ifindex)
{
struct net_device *dev = __dev_get_by_index(ctx->net, ifindex);
+ if (dev && !vrf_eq(dev_vrf(dev), ctx->vrf))
+ dev = NULL;
+
return dev;
}
EXPORT_SYMBOL(__dev_get_by_index_ctx);
@@ -814,6 +820,9 @@ struct net_device *dev_get_by_index_rcu_ctx(struct net_ctx *ctx, int ifindex)
{
struct net_device *dev = dev_get_by_index_rcu(ctx->net, ifindex);
+ if (dev && !vrf_eq(dev_vrf(dev), ctx->vrf))
+ dev = NULL;
+
return dev;
}
EXPORT_SYMBOL(dev_get_by_index_rcu_ctx);
@@ -317,7 +317,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
rule->iifindex = -1;
nla_strlcpy(rule->iifname, tb[FRA_IIFNAME], IFNAMSIZ);
- dev = __dev_get_by_name(net, rule->iifname);
+ dev = __dev_get_by_name_ctx(&sk_ctx, rule->iifname);
if (dev)
rule->iifindex = dev->ifindex;
}
@@ -327,7 +327,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
rule->oifindex = -1;
nla_strlcpy(rule->oifname, tb[FRA_OIFNAME], IFNAMSIZ);
- dev = __dev_get_by_name(net, rule->oifname);
+ dev = __dev_get_by_name_ctx(&sk_ctx, rule->oifname);
if (dev)
rule->oifindex = dev->ifindex;
}
@@ -2846,9 +2846,11 @@ static void neigh_copy_dflt_parms(struct net_ctx *ctx, struct neigh_parms *p,
rcu_read_lock();
for_each_netdev_rcu(ctx->net, dev) {
- struct neigh_parms *dst_p =
- neigh_get_dev_parms_rcu(dev, family);
+ struct neigh_parms *dst_p;
+ if (!vrf_eq(dev_vrf(dev), ctx->vrf))
+ continue;
+ dst_p = neigh_get_dev_parms_rcu(dev, family);
if (dst_p && !test_bit(index, dst_p->data_state))
dst_p->data[index] = p->data[index];
}
@@ -1021,6 +1021,8 @@ static int arp_req_set_public(struct net_ctx *ctx, struct arpreq *r,
if (!dev && (r->arp_flags & ATF_COM)) {
dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family,
r->arp_ha.sa_data);
+ if (dev && !vrf_eq(dev_vrf(dev), ctx->vrf))
+ dev = NULL;
if (!dev)
return -ENODEV;
}
@@ -1214,7 +1216,7 @@ int arp_ioctl(struct net_ctx *ctx, unsigned int cmd, void __user *arg)
rtnl_lock();
if (r.arp_dev[0]) {
err = -ENODEV;
- dev = __dev_get_by_name(net, r.arp_dev);
+ dev = __dev_get_by_name_ctx(ctx, r.arp_dev);
if (dev == NULL)
goto out;
@@ -951,7 +951,7 @@ int devinet_ioctl(struct net_ctx *net_ctx, unsigned int cmd, void __user *arg)
rtnl_lock();
ret = -ENODEV;
- dev = __dev_get_by_name(net, ifr.ifr_name);
+ dev = __dev_get_by_name_ctx(net_ctx, ifr.ifr_name);
if (!dev)
goto done;
@@ -1166,6 +1166,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
__be32 addr = 0;
struct in_device *in_dev;
struct net *net = dev_net(dev);
+ __u32 vrf = dev_vrf(dev);
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
@@ -1192,6 +1193,8 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
in dev_base list.
*/
for_each_netdev_rcu(net, dev) {
+ if (!vrf_eq(dev_vrf(dev), vrf))
+ continue;
in_dev = __in_dev_get_rcu(dev);
if (!in_dev)
continue;
@@ -1266,6 +1269,8 @@ __be32 inet_confirm_addr(struct net_ctx *ctx, struct in_device *in_dev,
rcu_read_lock();
for_each_netdev_rcu(ctx->net, dev) {
+ if (!vrf_eq(dev_vrf(dev), ctx->vrf))
+ continue;
in_dev = __in_dev_get_rcu(dev);
if (in_dev) {
addr = confirm_addr_indev(in_dev, dst, local, scope);
@@ -1561,6 +1566,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
goto cont;
if (h > s_h || idx > s_idx)
s_ip_idx = 0;
+ if (!vrf_eq(dev_vrf(dev), vrf))
+ goto cont;
in_dev = __in_dev_get_rcu(dev);
if (!in_dev)
goto cont;
@@ -1883,6 +1890,8 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb,
hlist_for_each_entry_rcu(dev, head, index_hlist) {
if (idx < s_idx)
goto cont;
+ if (!vrf_eq(dev_vrf(dev), vrf))
+ goto cont;
in_dev = __in_dev_get_rcu(dev);
if (!in_dev)
goto cont;
@@ -418,7 +418,7 @@ static int rtentry_to_fib_config(struct net_ctx *ctx, int cmd,
colon = strchr(devname, ':');
if (colon)
*colon = 0;
- dev = __dev_get_by_name(net, devname);
+ dev = __dev_get_by_name_ctx(ctx, devname);
if (!dev)
return -ENODEV;
cfg->fc_oif = dev->ifindex;
@@ -929,6 +929,11 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
err = -ENODEV;
if (nh->nh_dev == NULL)
goto failure;
+ if (!vrf_eq(dev_vrf(nh->nh_dev), net_ctx->vrf)) {
+ dev_put(nh->nh_dev);
+ nh->nh_dev = NULL;
+ goto failure;
+ }
} else {
change_nexthops(fi) {
err = fib_check_nh(cfg, fi, nexthop_nh);
@@ -2451,6 +2451,9 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
for_each_netdev_rcu(net, state->dev) {
struct in_device *in_dev;
+ if (!vrf_eq(dev_vrf(state->dev), ctx->vrf))
+ continue;
+
in_dev = __in_dev_get_rcu(state->dev);
if (!in_dev)
continue;
@@ -2596,6 +2599,10 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
state->im = NULL;
for_each_netdev_rcu(net, state->dev) {
struct in_device *idev;
+
+ if (!vrf_eq(dev_vrf(state->dev), ctx->vrf))
+ continue;
+
idev = __in_dev_get_rcu(state->dev);
if (unlikely(idev == NULL))
continue;
@@ -220,6 +220,8 @@ struct sock *__inet_lookup_listener(struct net_ctx *ctx,
result = NULL;
hiscore = 0;
sk_nulls_for_each_rcu(sk, node, &ilb->head) {
+ if (!vrf_eq(sk->sk_vrf, ctx->vrf) && !vrf_is_any(sk->sk_vrf))
+ continue;
score = compute_score(sk, ctx, hnum, daddr, dif);
if (score > hiscore) {
result = sk;
@@ -728,6 +728,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
{
struct net_device *dev = NULL;
int ifindex;
+ __u32 vrf;
if (optlen != sizeof(int))
goto e_inval;
@@ -743,7 +744,10 @@ static int do_ip_setsockopt(struct sock *sk, int level,
err = -EADDRNOTAVAIL;
if (!dev)
break;
+ vrf = dev_vrf(dev);
dev_put(dev);
+ if (!vrf_eq(vrf, sk_ctx.vrf))
+ break;
err = -EINVAL;
if (sk->sk_bound_dev_if)
Add vrf comparison to all of the net_ctx_eq functions and a few other places needed to enable vrf awareness. Signed-off-by: David Ahern <dsahern@gmail.com> --- include/linux/netdevice.h | 3 ++- include/net/inet_hashtables.h | 3 ++- include/net/ip_fib.h | 3 ++- include/net/ipv6.h | 2 +- include/net/neighbour.h | 6 ++++-- include/net/net_namespace.h | 2 +- include/net/sock.h | 2 +- net/core/dev.c | 9 +++++++++ net/core/fib_rules.c | 4 ++-- net/core/neighbour.c | 6 ++++-- net/ipv4/arp.c | 4 +++- net/ipv4/devinet.c | 11 ++++++++++- net/ipv4/fib_frontend.c | 2 +- net/ipv4/fib_semantics.c | 5 +++++ net/ipv4/igmp.c | 7 +++++++ net/ipv4/inet_hashtables.c | 2 ++ net/ipv4/ip_sockglue.c | 4 ++++ 17 files changed, 60 insertions(+), 15 deletions(-)