@@ -180,7 +180,7 @@ __be32 fib_info_update_nh_saddr(struct net_ctx *ctx, struct fib_nh *nh);
#define FIB_RES_SADDR(ctx, res) \
((FIB_RES_NH(res).nh_saddr_genid == \
- atomic_read(&(ctx)->net->ipv4.dev_addr_genid)) ? \
+ (atomic_read(&(ctx)->net->ipv4.dev_addr_genid) + (ctx)->vrf)) ? \
FIB_RES_NH(res).nh_saddr : \
fib_info_update_nh_saddr((ctx), &FIB_RES_NH(res)))
#define FIB_RES_GW(res) (FIB_RES_NH(res).nh_gw)
@@ -372,12 +372,14 @@ static inline void unregister_net_sysctl_table(struct ctl_table_header *header)
static inline int rt_genid_ipv4(struct net_ctx *ctx)
{
- return atomic_read(&ctx->net->ipv4.rt_genid);
+ return atomic_read(&ctx->net->ipv4.rt_genid) + ctx->vrf;
}
static inline void rt_genid_bump_ipv4(struct net *net)
{
- atomic_inc(&net->ipv4.rt_genid);
+ int inc = 1 << VRF_BITS;
+
+ atomic_add(inc, &net->ipv4.rt_genid);
}
extern void (*__fib6_flush_trees)(struct net *net);
@@ -404,12 +406,14 @@ static inline void rt_genid_bump_all(struct net *net)
static inline int fnhe_genid(struct net_ctx *ctx)
{
- return atomic_read(&ctx->net->fnhe_genid);
+ return atomic_read(&ctx->net->fnhe_genid) + ctx->vrf;
}
static inline void fnhe_genid_bump(struct net *net)
{
- atomic_inc(&net->fnhe_genid);
+ int inc = 1 << VRF_BITS;
+
+ atomic_add(inc, &net->fnhe_genid);
}
#endif /* __NET_NET_NAMESPACE_H */
@@ -1536,6 +1536,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net_ctx sk_ctx = SOCK_NET_CTX(skb->sk);
struct net *net = sk_ctx.net;
+ __u32 vrf = sk_ctx.vrf;
int h, s_h;
int idx, s_idx;
int ip_idx, s_ip_idx;
@@ -1549,11 +1550,12 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
s_ip_idx = ip_idx = cb->args[2];
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+ int genid;
idx = 0;
head = &net->dev_index_head[h];
rcu_read_lock();
- cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
- net->dev_base_seq;
+ genid = atomic_read(&net->ipv4.dev_addr_genid) + vrf;
+ cb->seq = genid ^ net->dev_base_seq;
hlist_for_each_entry_rcu(dev, head, index_hlist) {
if (idx < s_idx)
goto cont;
@@ -1861,6 +1863,7 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb,
{
struct net_ctx sk_ctx = SOCK_NET_CTX(skb->sk);
struct net *net = sk_ctx.net;
+ __u32 vrf = sk_ctx.vrf;
int h, s_h;
int idx, s_idx;
struct net_device *dev;
@@ -1871,11 +1874,12 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb,
s_idx = idx = cb->args[1];
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+ int genid;
idx = 0;
head = &net->dev_index_head[h];
rcu_read_lock();
- cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
- net->dev_base_seq;
+ genid = atomic_read(&net->ipv4.dev_addr_genid) + vrf;
+ cb->seq = genid ^ net->dev_base_seq;
hlist_for_each_entry_rcu(dev, head, index_hlist) {
if (idx < s_idx)
goto cont;
@@ -1021,6 +1021,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
struct net_device *dev = ifa->ifa_dev->dev;
struct net *net = dev_net(dev);
+ int inc = 1 << VRF_BITS;
switch (event) {
case NETDEV_UP:
@@ -1028,12 +1029,12 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
#ifdef CONFIG_IP_ROUTE_MULTIPATH
fib_sync_up(dev);
#endif
- atomic_inc(&net->ipv4.dev_addr_genid);
+ atomic_add(inc, &net->ipv4.dev_addr_genid);
rt_cache_flush(dev_net(dev));
break;
case NETDEV_DOWN:
fib_del_ifaddr(ifa, NULL);
- atomic_inc(&net->ipv4.dev_addr_genid);
+ atomic_add(inc, &net->ipv4.dev_addr_genid);
if (ifa->ifa_dev->ifa_list == NULL) {
/* Last address was deleted from this interface.
* Disable IP.
@@ -1052,6 +1053,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct in_device *in_dev;
struct net *net = dev_net(dev);
+ int inc = 1 << VRF_BITS;
if (event == NETDEV_UNREGISTER) {
fib_disable_ip(dev, 2);
@@ -1071,7 +1073,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
#ifdef CONFIG_IP_ROUTE_MULTIPATH
fib_sync_up(dev);
#endif
- atomic_inc(&net->ipv4.dev_addr_genid);
+ atomic_add(inc, &net->ipv4.dev_addr_genid);
rt_cache_flush(net);
break;
case NETDEV_DOWN:
@@ -756,7 +756,7 @@ __be32 fib_info_update_nh_saddr(struct net_ctx *net_ctx, struct fib_nh *nh)
nh->nh_saddr = inet_select_addr(nh->nh_dev,
nh->nh_gw,
nh->nh_parent->fib_scope);
- nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid);
+ nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid) + net_ctx->vrf;
return nh->nh_saddr;
}
@@ -2706,10 +2706,19 @@ static __net_initdata struct pernet_operations sysctl_route_ops = {
static __net_init int rt_genid_init(struct net *net)
{
+ int genid;
+
atomic_set(&net->ipv4.rt_genid, 0);
atomic_set(&net->fnhe_genid, 0);
- get_random_bytes(&net->ipv4.dev_addr_genid,
- sizeof(net->ipv4.dev_addr_genid));
+
+again:
+ get_random_bytes(&genid, sizeof(genid));
+ genid &= ~VRF_MASK;
+ if (genid == 0)
+ goto again;
+
+ atomic_set(&net->ipv4.dev_addr_genid, genid);
+
return 0;
}
Bottom 12 bits (VRF_BITS) are the VRF id. Signed-off-by: David Ahern <dsahern@gmail.com> --- include/net/ip_fib.h | 2 +- include/net/net_namespace.h | 12 ++++++++---- net/ipv4/devinet.c | 12 ++++++++---- net/ipv4/fib_frontend.c | 8 +++++--- net/ipv4/fib_semantics.c | 2 +- net/ipv4/route.c | 13 +++++++++++-- 6 files changed, 34 insertions(+), 15 deletions(-)