diff options
author | David Miller <davem@davemloft.net> | 2017-11-28 15:40:40 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-11-30 09:54:26 -0500 |
commit | 3a2232e92e87166a8a5113e918b8c7b7bdce4d83 (patch) | |
tree | d4bea5d4b31fe38dde724e8eb102038438f17f36 | |
parent | b6ca8bd5a9198c70c48297390723e4e56bd6e879 (diff) |
ipv6: Move dst->from into struct rt6_info.
The dst->from value is only used by ipv6 routes to track where
a route "came from".
Any time we clone or copy a core ipv6 route in the ipv6 routing
tables, we have the copy/clone's ->from point to the base route.
This is used to handle route expiration properly.
Only ipv6 uses this mechanism, and only ipv6 code references
it. So it is safe to move it into rt6_info.
Signed-off-by: David S. Miller <davem@davemloft.net>
Reviewed-by: Eric Dumazet <edumazet@google.com>
-rw-r--r-- | include/net/dst.h | 3 | ||||
-rw-r--r-- | include/net/ip6_fib.h | 9 | ||||
-rw-r--r-- | net/core/dst.c | 1 | ||||
-rw-r--r-- | net/ipv6/route.c | 34 |
4 files changed, 22 insertions, 25 deletions
diff --git a/include/net/dst.h b/include/net/dst.h index cef46207408c..13c839d8235a 100644 --- a/include/net/dst.h +++ b/include/net/dst.h | |||
@@ -39,7 +39,6 @@ struct dst_entry { | |||
39 | unsigned long _metrics; | 39 | unsigned long _metrics; |
40 | unsigned long expires; | 40 | unsigned long expires; |
41 | struct dst_entry *path; | 41 | struct dst_entry *path; |
42 | struct dst_entry *from; | ||
43 | #ifdef CONFIG_XFRM | 42 | #ifdef CONFIG_XFRM |
44 | struct xfrm_state *xfrm; | 43 | struct xfrm_state *xfrm; |
45 | #else | 44 | #else |
@@ -88,7 +87,7 @@ struct dst_entry { | |||
88 | * Align __refcnt to a 64 bytes alignment | 87 | * Align __refcnt to a 64 bytes alignment |
89 | * (L1_CACHE_SIZE would be too much) | 88 | * (L1_CACHE_SIZE would be too much) |
90 | */ | 89 | */ |
91 | long __pad_to_align_refcnt[3]; | 90 | long __pad_to_align_refcnt[4]; |
92 | #endif | 91 | #endif |
93 | /* | 92 | /* |
94 | * __refcnt wants to be on a different cache line from | 93 | * __refcnt wants to be on a different cache line from |
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 281a922f0c62..44d96a91e745 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h | |||
@@ -130,6 +130,7 @@ struct rt6_exception { | |||
130 | struct rt6_info { | 130 | struct rt6_info { |
131 | struct dst_entry dst; | 131 | struct dst_entry dst; |
132 | struct rt6_info __rcu *rt6_next; | 132 | struct rt6_info __rcu *rt6_next; |
133 | struct rt6_info *from; | ||
133 | 134 | ||
134 | /* | 135 | /* |
135 | * Tail elements of dst_entry (__refcnt etc.) | 136 | * Tail elements of dst_entry (__refcnt etc.) |
@@ -204,11 +205,9 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) | |||
204 | { | 205 | { |
205 | struct rt6_info *rt; | 206 | struct rt6_info *rt; |
206 | 207 | ||
207 | for (rt = rt0; rt && !(rt->rt6i_flags & RTF_EXPIRES); | 208 | for (rt = rt0; rt && !(rt->rt6i_flags & RTF_EXPIRES); rt = rt->from); |
208 | rt = (struct rt6_info *)rt->dst.from); | ||
209 | if (rt && rt != rt0) | 209 | if (rt && rt != rt0) |
210 | rt0->dst.expires = rt->dst.expires; | 210 | rt0->dst.expires = rt->dst.expires; |
211 | |||
212 | dst_set_expires(&rt0->dst, timeout); | 211 | dst_set_expires(&rt0->dst, timeout); |
213 | rt0->rt6i_flags |= RTF_EXPIRES; | 212 | rt0->rt6i_flags |= RTF_EXPIRES; |
214 | } | 213 | } |
@@ -243,8 +242,8 @@ static inline u32 rt6_get_cookie(const struct rt6_info *rt) | |||
243 | u32 cookie = 0; | 242 | u32 cookie = 0; |
244 | 243 | ||
245 | if (rt->rt6i_flags & RTF_PCPU || | 244 | if (rt->rt6i_flags & RTF_PCPU || |
246 | (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->dst.from)) | 245 | (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->from)) |
247 | rt = (struct rt6_info *)(rt->dst.from); | 246 | rt = rt->from; |
248 | 247 | ||
249 | rt6_get_cookie_safe(rt, &cookie); | 248 | rt6_get_cookie_safe(rt, &cookie); |
250 | 249 | ||
diff --git a/net/core/dst.c b/net/core/dst.c index 5cf96179e8e0..cf2076c0eb22 100644 --- a/net/core/dst.c +++ b/net/core/dst.c | |||
@@ -70,7 +70,6 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops, | |||
70 | dst_init_metrics(dst, dst_default_metrics.metrics, true); | 70 | dst_init_metrics(dst, dst_default_metrics.metrics, true); |
71 | dst->expires = 0UL; | 71 | dst->expires = 0UL; |
72 | dst->path = dst; | 72 | dst->path = dst; |
73 | dst->from = NULL; | ||
74 | #ifdef CONFIG_XFRM | 73 | #ifdef CONFIG_XFRM |
75 | dst->xfrm = NULL; | 74 | dst->xfrm = NULL; |
76 | #endif | 75 | #endif |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 22c5e70361d6..1f1ef1e071c2 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -186,7 +186,7 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev) | |||
186 | 186 | ||
187 | static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt) | 187 | static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt) |
188 | { | 188 | { |
189 | return dst_metrics_write_ptr(rt->dst.from); | 189 | return dst_metrics_write_ptr(&rt->from->dst); |
190 | } | 190 | } |
191 | 191 | ||
192 | static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) | 192 | static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) |
@@ -391,7 +391,7 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
391 | { | 391 | { |
392 | struct rt6_info *rt = (struct rt6_info *)dst; | 392 | struct rt6_info *rt = (struct rt6_info *)dst; |
393 | struct rt6_exception_bucket *bucket; | 393 | struct rt6_exception_bucket *bucket; |
394 | struct dst_entry *from = dst->from; | 394 | struct rt6_info *from = rt->from; |
395 | struct inet6_dev *idev; | 395 | struct inet6_dev *idev; |
396 | 396 | ||
397 | dst_destroy_metrics_generic(dst); | 397 | dst_destroy_metrics_generic(dst); |
@@ -409,8 +409,8 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
409 | kfree(bucket); | 409 | kfree(bucket); |
410 | } | 410 | } |
411 | 411 | ||
412 | dst->from = NULL; | 412 | rt->from = NULL; |
413 | dst_release(from); | 413 | dst_release(&from->dst); |
414 | } | 414 | } |
415 | 415 | ||
416 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 416 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
@@ -443,9 +443,9 @@ static bool rt6_check_expired(const struct rt6_info *rt) | |||
443 | if (rt->rt6i_flags & RTF_EXPIRES) { | 443 | if (rt->rt6i_flags & RTF_EXPIRES) { |
444 | if (time_after(jiffies, rt->dst.expires)) | 444 | if (time_after(jiffies, rt->dst.expires)) |
445 | return true; | 445 | return true; |
446 | } else if (rt->dst.from) { | 446 | } else if (rt->from) { |
447 | return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK || | 447 | return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK || |
448 | rt6_check_expired((struct rt6_info *)rt->dst.from); | 448 | rt6_check_expired(rt->from); |
449 | } | 449 | } |
450 | return false; | 450 | return false; |
451 | } | 451 | } |
@@ -1054,7 +1054,7 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort, | |||
1054 | */ | 1054 | */ |
1055 | 1055 | ||
1056 | if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) | 1056 | if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) |
1057 | ort = (struct rt6_info *)ort->dst.from; | 1057 | ort = ort->from; |
1058 | 1058 | ||
1059 | rcu_read_lock(); | 1059 | rcu_read_lock(); |
1060 | dev = ip6_rt_get_dev_rcu(ort); | 1060 | dev = ip6_rt_get_dev_rcu(ort); |
@@ -1274,7 +1274,7 @@ static int rt6_insert_exception(struct rt6_info *nrt, | |||
1274 | 1274 | ||
1275 | /* ort can't be a cache or pcpu route */ | 1275 | /* ort can't be a cache or pcpu route */ |
1276 | if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) | 1276 | if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) |
1277 | ort = (struct rt6_info *)ort->dst.from; | 1277 | ort = ort->from; |
1278 | WARN_ON_ONCE(ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)); | 1278 | WARN_ON_ONCE(ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)); |
1279 | 1279 | ||
1280 | spin_lock_bh(&rt6_exception_lock); | 1280 | spin_lock_bh(&rt6_exception_lock); |
@@ -1415,8 +1415,8 @@ static struct rt6_info *rt6_find_cached_rt(struct rt6_info *rt, | |||
1415 | /* Remove the passed in cached rt from the hash table that contains it */ | 1415 | /* Remove the passed in cached rt from the hash table that contains it */ |
1416 | int rt6_remove_exception_rt(struct rt6_info *rt) | 1416 | int rt6_remove_exception_rt(struct rt6_info *rt) |
1417 | { | 1417 | { |
1418 | struct rt6_info *from = (struct rt6_info *)rt->dst.from; | ||
1419 | struct rt6_exception_bucket *bucket; | 1418 | struct rt6_exception_bucket *bucket; |
1419 | struct rt6_info *from = rt->from; | ||
1420 | struct in6_addr *src_key = NULL; | 1420 | struct in6_addr *src_key = NULL; |
1421 | struct rt6_exception *rt6_ex; | 1421 | struct rt6_exception *rt6_ex; |
1422 | int err; | 1422 | int err; |
@@ -1460,8 +1460,8 @@ int rt6_remove_exception_rt(struct rt6_info *rt) | |||
1460 | */ | 1460 | */ |
1461 | static void rt6_update_exception_stamp_rt(struct rt6_info *rt) | 1461 | static void rt6_update_exception_stamp_rt(struct rt6_info *rt) |
1462 | { | 1462 | { |
1463 | struct rt6_info *from = (struct rt6_info *)rt->dst.from; | ||
1464 | struct rt6_exception_bucket *bucket; | 1463 | struct rt6_exception_bucket *bucket; |
1464 | struct rt6_info *from = rt->from; | ||
1465 | struct in6_addr *src_key = NULL; | 1465 | struct in6_addr *src_key = NULL; |
1466 | struct rt6_exception *rt6_ex; | 1466 | struct rt6_exception *rt6_ex; |
1467 | 1467 | ||
@@ -1929,9 +1929,9 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori | |||
1929 | 1929 | ||
1930 | static void rt6_dst_from_metrics_check(struct rt6_info *rt) | 1930 | static void rt6_dst_from_metrics_check(struct rt6_info *rt) |
1931 | { | 1931 | { |
1932 | if (rt->dst.from && | 1932 | if (rt->from && |
1933 | dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from)) | 1933 | dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(&rt->from->dst)) |
1934 | dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true); | 1934 | dst_init_metrics(&rt->dst, dst_metrics_ptr(&rt->from->dst), true); |
1935 | } | 1935 | } |
1936 | 1936 | ||
1937 | static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie) | 1937 | static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie) |
@@ -1951,7 +1951,7 @@ static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie) | |||
1951 | { | 1951 | { |
1952 | if (!__rt6_check_expired(rt) && | 1952 | if (!__rt6_check_expired(rt) && |
1953 | rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && | 1953 | rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && |
1954 | rt6_check((struct rt6_info *)(rt->dst.from), cookie)) | 1954 | rt6_check(rt->from, cookie)) |
1955 | return &rt->dst; | 1955 | return &rt->dst; |
1956 | else | 1956 | else |
1957 | return NULL; | 1957 | return NULL; |
@@ -1971,7 +1971,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) | |||
1971 | rt6_dst_from_metrics_check(rt); | 1971 | rt6_dst_from_metrics_check(rt); |
1972 | 1972 | ||
1973 | if (rt->rt6i_flags & RTF_PCPU || | 1973 | if (rt->rt6i_flags & RTF_PCPU || |
1974 | (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->dst.from)) | 1974 | (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->from)) |
1975 | return rt6_dst_from_check(rt, cookie); | 1975 | return rt6_dst_from_check(rt, cookie); |
1976 | else | 1976 | else |
1977 | return rt6_check(rt, cookie); | 1977 | return rt6_check(rt, cookie); |
@@ -3055,11 +3055,11 @@ out: | |||
3055 | 3055 | ||
3056 | static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) | 3056 | static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) |
3057 | { | 3057 | { |
3058 | BUG_ON(from->dst.from); | 3058 | BUG_ON(from->from); |
3059 | 3059 | ||
3060 | rt->rt6i_flags &= ~RTF_EXPIRES; | 3060 | rt->rt6i_flags &= ~RTF_EXPIRES; |
3061 | dst_hold(&from->dst); | 3061 | dst_hold(&from->dst); |
3062 | rt->dst.from = &from->dst; | 3062 | rt->from = from; |
3063 | dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true); | 3063 | dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true); |
3064 | } | 3064 | } |
3065 | 3065 | ||