aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfan.du <fan.du@windriver.com>2013-07-29 20:33:53 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-31 17:56:36 -0400
commitca4c3fc24e293719fe7410c4e63da9b6bc633b83 (patch)
tree0461841f3d10b11a26ebe1a0adc99c7b00a489a2
parentba361cb3d4c977e2b94b5d97905f66b4d48964de (diff)
net: split rt_genid for ipv4 and ipv6
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>
-rw-r--r--include/net/net_namespace.h37
-rw-r--r--include/net/netns/ipv4.h1
-rw-r--r--include/net/netns/ipv6.h1
-rw-r--r--net/ipv4/route.c16
-rw-r--r--net/ipv6/af_inet6.c1
-rw-r--r--net/ipv6/route.c4
-rw-r--r--net/xfrm/xfrm_policy.c8
-rw-r--r--security/selinux/include/xfrm.h7
8 files changed, 58 insertions, 17 deletions
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 84e37b1ca9e1..1313456a0994 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -119,7 +119,6 @@ struct net {
119 struct netns_ipvs *ipvs; 119 struct netns_ipvs *ipvs;
120#endif 120#endif
121 struct sock *diag_nlsk; 121 struct sock *diag_nlsk;
122 atomic_t rt_genid;
123 atomic_t fnhe_genid; 122 atomic_t fnhe_genid;
124}; 123};
125 124
@@ -333,14 +332,42 @@ static inline void unregister_net_sysctl_table(struct ctl_table_header *header)
333} 332}
334#endif 333#endif
335 334
336static inline int rt_genid(struct net *net) 335static inline int rt_genid_ipv4(struct net *net)
337{ 336{
338 return atomic_read(&net->rt_genid); 337 return atomic_read(&net->ipv4.rt_genid);
339} 338}
340 339
341static inline void rt_genid_bump(struct net *net) 340static inline void rt_genid_bump_ipv4(struct net *net)
342{ 341{
343 atomic_inc(&net->rt_genid); 342 atomic_inc(&net->ipv4.rt_genid);
343}
344
345#if IS_ENABLED(CONFIG_IPV6)
346static inline int rt_genid_ipv6(struct net *net)
347{
348 return atomic_read(&net->ipv6.rt_genid);
349}
350
351static inline void rt_genid_bump_ipv6(struct net *net)
352{
353 atomic_inc(&net->ipv6.rt_genid);
354}
355#else
356static inline int rt_genid_ipv6(struct net *net)
357{
358 return 0;
359}
360
361static inline void rt_genid_bump_ipv6(struct net *net)
362{
363}
364#endif
365
366/* For callers who don't really care about whether it's IPv4 or IPv6 */
367static inline void rt_genid_bump_all(struct net *net)
368{
369 rt_genid_bump_ipv4(net);
370 rt_genid_bump_ipv6(net);
344} 371}
345 372
346static inline int fnhe_genid(struct net *net) 373static inline int fnhe_genid(struct net *net)
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 2ba9de89e8ec..bf2ec2202c56 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -77,5 +77,6 @@ struct netns_ipv4 {
77 struct fib_rules_ops *mr_rules_ops; 77 struct fib_rules_ops *mr_rules_ops;
78#endif 78#endif
79#endif 79#endif
80 atomic_t rt_genid;
80}; 81};
81#endif 82#endif
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 005e2c2e39a9..0fb2401197c5 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -72,6 +72,7 @@ struct netns_ipv6 {
72#endif 72#endif
73#endif 73#endif
74 atomic_t dev_addr_genid; 74 atomic_t dev_addr_genid;
75 atomic_t rt_genid;
75}; 76};
76 77
77#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) 78#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index a9a54a236832..e805481eff72 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -435,12 +435,12 @@ static inline int ip_rt_proc_init(void)
435 435
436static inline bool rt_is_expired(const struct rtable *rth) 436static inline bool rt_is_expired(const struct rtable *rth)
437{ 437{
438 return rth->rt_genid != rt_genid(dev_net(rth->dst.dev)); 438 return rth->rt_genid != rt_genid_ipv4(dev_net(rth->dst.dev));
439} 439}
440 440
441void rt_cache_flush(struct net *net) 441void rt_cache_flush(struct net *net)
442{ 442{
443 rt_genid_bump(net); 443 rt_genid_bump_ipv4(net);
444} 444}
445 445
446static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, 446static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
@@ -1458,7 +1458,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1458#endif 1458#endif
1459 rth->dst.output = ip_rt_bug; 1459 rth->dst.output = ip_rt_bug;
1460 1460
1461 rth->rt_genid = rt_genid(dev_net(dev)); 1461 rth->rt_genid = rt_genid_ipv4(dev_net(dev));
1462 rth->rt_flags = RTCF_MULTICAST; 1462 rth->rt_flags = RTCF_MULTICAST;
1463 rth->rt_type = RTN_MULTICAST; 1463 rth->rt_type = RTN_MULTICAST;
1464 rth->rt_is_input= 1; 1464 rth->rt_is_input= 1;
@@ -1589,7 +1589,7 @@ static int __mkroute_input(struct sk_buff *skb,
1589 goto cleanup; 1589 goto cleanup;
1590 } 1590 }
1591 1591
1592 rth->rt_genid = rt_genid(dev_net(rth->dst.dev)); 1592 rth->rt_genid = rt_genid_ipv4(dev_net(rth->dst.dev));
1593 rth->rt_flags = flags; 1593 rth->rt_flags = flags;
1594 rth->rt_type = res->type; 1594 rth->rt_type = res->type;
1595 rth->rt_is_input = 1; 1595 rth->rt_is_input = 1;
@@ -1760,7 +1760,7 @@ local_input:
1760 rth->dst.tclassid = itag; 1760 rth->dst.tclassid = itag;
1761#endif 1761#endif
1762 1762
1763 rth->rt_genid = rt_genid(net); 1763 rth->rt_genid = rt_genid_ipv4(net);
1764 rth->rt_flags = flags|RTCF_LOCAL; 1764 rth->rt_flags = flags|RTCF_LOCAL;
1765 rth->rt_type = res.type; 1765 rth->rt_type = res.type;
1766 rth->rt_is_input = 1; 1766 rth->rt_is_input = 1;
@@ -1945,7 +1945,7 @@ add:
1945 1945
1946 rth->dst.output = ip_output; 1946 rth->dst.output = ip_output;
1947 1947
1948 rth->rt_genid = rt_genid(dev_net(dev_out)); 1948 rth->rt_genid = rt_genid_ipv4(dev_net(dev_out));
1949 rth->rt_flags = flags; 1949 rth->rt_flags = flags;
1950 rth->rt_type = type; 1950 rth->rt_type = type;
1951 rth->rt_is_input = 0; 1951 rth->rt_is_input = 0;
@@ -2227,7 +2227,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
2227 rt->rt_iif = ort->rt_iif; 2227 rt->rt_iif = ort->rt_iif;
2228 rt->rt_pmtu = ort->rt_pmtu; 2228 rt->rt_pmtu = ort->rt_pmtu;
2229 2229
2230 rt->rt_genid = rt_genid(net); 2230 rt->rt_genid = rt_genid_ipv4(net);
2231 rt->rt_flags = ort->rt_flags; 2231 rt->rt_flags = ort->rt_flags;
2232 rt->rt_type = ort->rt_type; 2232 rt->rt_type = ort->rt_type;
2233 rt->rt_gateway = ort->rt_gateway; 2233 rt->rt_gateway = ort->rt_gateway;
@@ -2665,7 +2665,7 @@ static __net_initdata struct pernet_operations sysctl_route_ops = {
2665 2665
2666static __net_init int rt_genid_init(struct net *net) 2666static __net_init int rt_genid_init(struct net *net)
2667{ 2667{
2668 atomic_set(&net->rt_genid, 0); 2668 atomic_set(&net->ipv4.rt_genid, 0);
2669 atomic_set(&net->fnhe_genid, 0); 2669 atomic_set(&net->fnhe_genid, 0);
2670 get_random_bytes(&net->ipv4.dev_addr_genid, 2670 get_random_bytes(&net->ipv4.dev_addr_genid,
2671 sizeof(net->ipv4.dev_addr_genid)); 2671 sizeof(net->ipv4.dev_addr_genid));
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index a5ac969aeefe..0d1a9b153fbb 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -766,6 +766,7 @@ static int __net_init inet6_net_init(struct net *net)
766 766
767 net->ipv6.sysctl.bindv6only = 0; 767 net->ipv6.sysctl.bindv6only = 0;
768 net->ipv6.sysctl.icmpv6_time = 1*HZ; 768 net->ipv6.sysctl.icmpv6_time = 1*HZ;
769 atomic_set(&net->ipv6.rt_genid, 0);
769 770
770 err = ipv6_init_mibs(net); 771 err = ipv6_init_mibs(net);
771 if (err) 772 if (err)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 74ab1f74abcd..ce9616304521 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -283,7 +283,7 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net,
283 283
284 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); 284 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
285 rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers); 285 rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
286 rt->rt6i_genid = rt_genid(net); 286 rt->rt6i_genid = rt_genid_ipv6(net);
287 INIT_LIST_HEAD(&rt->rt6i_siblings); 287 INIT_LIST_HEAD(&rt->rt6i_siblings);
288 } 288 }
289 return rt; 289 return rt;
@@ -1061,7 +1061,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1061 * DST_OBSOLETE_FORCE_CHK which forces validation calls down 1061 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1062 * into this function always. 1062 * into this function always.
1063 */ 1063 */
1064 if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev))) 1064 if (rt->rt6i_genid != rt_genid_ipv6(dev_net(rt->dst.dev)))
1065 return NULL; 1065 return NULL;
1066 1066
1067 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) 1067 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index e52cab3591dd..d8da6b8c6ba8 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -660,7 +660,13 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
660 xfrm_pol_hold(policy); 660 xfrm_pol_hold(policy);
661 net->xfrm.policy_count[dir]++; 661 net->xfrm.policy_count[dir]++;
662 atomic_inc(&flow_cache_genid); 662 atomic_inc(&flow_cache_genid);
663 rt_genid_bump(net); 663
664 /* After previous checking, family can either be AF_INET or AF_INET6 */
665 if (policy->family == AF_INET)
666 rt_genid_bump_ipv4(net);
667 else
668 rt_genid_bump_ipv6(net);
669
664 if (delpol) { 670 if (delpol) {
665 xfrm_policy_requeue(delpol, policy); 671 xfrm_policy_requeue(delpol, policy);
666 __xfrm_policy_unlink(delpol, dir); 672 __xfrm_policy_unlink(delpol, dir);
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 65f67cb0aefb..6713f04e30ba 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -50,8 +50,13 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
50 50
51static inline void selinux_xfrm_notify_policyload(void) 51static inline void selinux_xfrm_notify_policyload(void)
52{ 52{
53 struct net *net;
54
53 atomic_inc(&flow_cache_genid); 55 atomic_inc(&flow_cache_genid);
54 rt_genid_bump(&init_net); 56 rtnl_lock();
57 for_each_net(net)
58 rt_genid_bump_all(net);
59 rtnl_unlock();
55} 60}
56#else 61#else
57static inline int selinux_xfrm_enabled(void) 62static inline int selinux_xfrm_enabled(void)