Skip to content

Commit

Permalink
net: split rt_genid for ipv4 and ipv6
Browse files Browse the repository at this point in the history
Current net name space has only one genid for both IPv4 and IPv6, it has below
drawbacks:

- Add/delete an IPv4 address will invalidate all IPv6 routing table entries.
- Insert/remove XFRM policy will also invalidate both IPv4/IPv6 routing table
  entries even when the policy is only applied for one address family.

Thus, this patch attempt to split one genid for two to cater for IPv4 and IPv6
separately in a fine granularity.

Signed-off-by: Fan Du <fan.du@windriver.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
fan.du authored and David S. Miller committed Jul 31, 2013
1 parent ba361cb commit ca4c3fc
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 17 deletions.
37 changes: 32 additions & 5 deletions include/net/net_namespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ struct net {
struct netns_ipvs *ipvs;
#endif
struct sock *diag_nlsk;
atomic_t rt_genid;
atomic_t fnhe_genid;
};

Expand Down Expand Up @@ -333,14 +332,42 @@ static inline void unregister_net_sysctl_table(struct ctl_table_header *header)
}
#endif

static inline int rt_genid(struct net *net)
static inline int rt_genid_ipv4(struct net *net)
{
return atomic_read(&net->rt_genid);
return atomic_read(&net->ipv4.rt_genid);
}

static inline void rt_genid_bump(struct net *net)
static inline void rt_genid_bump_ipv4(struct net *net)
{
atomic_inc(&net->rt_genid);
atomic_inc(&net->ipv4.rt_genid);
}

#if IS_ENABLED(CONFIG_IPV6)
static inline int rt_genid_ipv6(struct net *net)
{
return atomic_read(&net->ipv6.rt_genid);
}

static inline void rt_genid_bump_ipv6(struct net *net)
{
atomic_inc(&net->ipv6.rt_genid);
}
#else
static inline int rt_genid_ipv6(struct net *net)
{
return 0;
}

static inline void rt_genid_bump_ipv6(struct net *net)
{
}
#endif

/* For callers who don't really care about whether it's IPv4 or IPv6 */
static inline void rt_genid_bump_all(struct net *net)
{
rt_genid_bump_ipv4(net);
rt_genid_bump_ipv6(net);
}

static inline int fnhe_genid(struct net *net)
Expand Down
1 change: 1 addition & 0 deletions include/net/netns/ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,6 @@ struct netns_ipv4 {
struct fib_rules_ops *mr_rules_ops;
#endif
#endif
atomic_t rt_genid;
};
#endif
1 change: 1 addition & 0 deletions include/net/netns/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ struct netns_ipv6 {
#endif
#endif
atomic_t dev_addr_genid;
atomic_t rt_genid;
};

#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
Expand Down
16 changes: 8 additions & 8 deletions net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,12 +435,12 @@ static inline int ip_rt_proc_init(void)

static inline bool rt_is_expired(const struct rtable *rth)
{
return rth->rt_genid != rt_genid(dev_net(rth->dst.dev));
return rth->rt_genid != rt_genid_ipv4(dev_net(rth->dst.dev));
}

void rt_cache_flush(struct net *net)
{
rt_genid_bump(net);
rt_genid_bump_ipv4(net);
}

static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
Expand Down Expand Up @@ -1458,7 +1458,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
#endif
rth->dst.output = ip_rt_bug;

rth->rt_genid = rt_genid(dev_net(dev));
rth->rt_genid = rt_genid_ipv4(dev_net(dev));
rth->rt_flags = RTCF_MULTICAST;
rth->rt_type = RTN_MULTICAST;
rth->rt_is_input= 1;
Expand Down Expand Up @@ -1589,7 +1589,7 @@ static int __mkroute_input(struct sk_buff *skb,
goto cleanup;
}

rth->rt_genid = rt_genid(dev_net(rth->dst.dev));
rth->rt_genid = rt_genid_ipv4(dev_net(rth->dst.dev));
rth->rt_flags = flags;
rth->rt_type = res->type;
rth->rt_is_input = 1;
Expand Down Expand Up @@ -1760,7 +1760,7 @@ out: return err;
rth->dst.tclassid = itag;
#endif

rth->rt_genid = rt_genid(net);
rth->rt_genid = rt_genid_ipv4(net);
rth->rt_flags = flags|RTCF_LOCAL;
rth->rt_type = res.type;
rth->rt_is_input = 1;
Expand Down Expand Up @@ -1945,7 +1945,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,

rth->dst.output = ip_output;

rth->rt_genid = rt_genid(dev_net(dev_out));
rth->rt_genid = rt_genid_ipv4(dev_net(dev_out));
rth->rt_flags = flags;
rth->rt_type = type;
rth->rt_is_input = 0;
Expand Down Expand Up @@ -2227,7 +2227,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
rt->rt_iif = ort->rt_iif;
rt->rt_pmtu = ort->rt_pmtu;

rt->rt_genid = rt_genid(net);
rt->rt_genid = rt_genid_ipv4(net);
rt->rt_flags = ort->rt_flags;
rt->rt_type = ort->rt_type;
rt->rt_gateway = ort->rt_gateway;
Expand Down Expand Up @@ -2665,7 +2665,7 @@ static __net_initdata struct pernet_operations sysctl_route_ops = {

static __net_init int rt_genid_init(struct net *net)
{
atomic_set(&net->rt_genid, 0);
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));
Expand Down
1 change: 1 addition & 0 deletions net/ipv6/af_inet6.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ static int __net_init inet6_net_init(struct net *net)

net->ipv6.sysctl.bindv6only = 0;
net->ipv6.sysctl.icmpv6_time = 1*HZ;
atomic_set(&net->ipv6.rt_genid, 0);

err = ipv6_init_mibs(net);
if (err)
Expand Down
4 changes: 2 additions & 2 deletions net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net,

memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
rt->rt6i_genid = rt_genid(net);
rt->rt6i_genid = rt_genid_ipv6(net);
INIT_LIST_HEAD(&rt->rt6i_siblings);
}
return rt;
Expand Down Expand Up @@ -1061,7 +1061,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
* DST_OBSOLETE_FORCE_CHK which forces validation calls down
* into this function always.
*/
if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev)))
if (rt->rt6i_genid != rt_genid_ipv6(dev_net(rt->dst.dev)))
return NULL;

if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
Expand Down
8 changes: 7 additions & 1 deletion net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,13 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
xfrm_pol_hold(policy);
net->xfrm.policy_count[dir]++;
atomic_inc(&flow_cache_genid);
rt_genid_bump(net);

/* After previous checking, family can either be AF_INET or AF_INET6 */
if (policy->family == AF_INET)
rt_genid_bump_ipv4(net);
else
rt_genid_bump_ipv6(net);

if (delpol) {
xfrm_policy_requeue(delpol, policy);
__xfrm_policy_unlink(delpol, dir);
Expand Down
7 changes: 6 additions & 1 deletion security/selinux/include/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);

static inline void selinux_xfrm_notify_policyload(void)
{
struct net *net;

atomic_inc(&flow_cache_genid);
rt_genid_bump(&init_net);
rtnl_lock();
for_each_net(net)
rt_genid_bump_all(net);
rtnl_unlock();
}
#else
static inline int selinux_xfrm_enabled(void)
Expand Down

0 comments on commit ca4c3fc

Please sign in to comment.