diff options
-rw-r--r-- | include/net/ip6_fib.h | 1 | ||||
-rw-r--r-- | include/net/route.h | 1 | ||||
-rw-r--r-- | net/ipv4/route.c | 19 | ||||
-rw-r--r-- | net/ipv6/route.c | 18 |
4 files changed, 36 insertions, 3 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 708ff7cb8806..46a6e8ae232c 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h | |||
@@ -108,6 +108,7 @@ struct rt6_info { | |||
108 | u32 rt6i_flags; | 108 | u32 rt6i_flags; |
109 | struct rt6key rt6i_src; | 109 | struct rt6key rt6i_src; |
110 | u32 rt6i_metric; | 110 | u32 rt6i_metric; |
111 | u32 rt6i_peer_genid; | ||
111 | 112 | ||
112 | struct inet6_dev *rt6i_idev; | 113 | struct inet6_dev *rt6i_idev; |
113 | struct inet_peer *rt6i_peer; | 114 | struct inet_peer *rt6i_peer; |
diff --git a/include/net/route.h b/include/net/route.h index e5864658dc76..bf790c1c6ac8 100644 --- a/include/net/route.h +++ b/include/net/route.h | |||
@@ -69,6 +69,7 @@ struct rtable { | |||
69 | 69 | ||
70 | /* Miscellaneous cached information */ | 70 | /* Miscellaneous cached information */ |
71 | __be32 rt_spec_dst; /* RFC1122 specific destination */ | 71 | __be32 rt_spec_dst; /* RFC1122 specific destination */ |
72 | u32 rt_peer_genid; | ||
72 | struct inet_peer *peer; /* long-living peer info */ | 73 | struct inet_peer *peer; /* long-living peer info */ |
73 | struct fib_info *fi; /* for client ref to shared metrics */ | 74 | struct fib_info *fi; /* for client ref to shared metrics */ |
74 | }; | 75 | }; |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 0455af851751..0979e039104a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1308,6 +1308,13 @@ skip_hashing: | |||
1308 | return 0; | 1308 | return 0; |
1309 | } | 1309 | } |
1310 | 1310 | ||
1311 | static atomic_t __rt_peer_genid = ATOMIC_INIT(0); | ||
1312 | |||
1313 | static u32 rt_peer_genid(void) | ||
1314 | { | ||
1315 | return atomic_read(&__rt_peer_genid); | ||
1316 | } | ||
1317 | |||
1311 | void rt_bind_peer(struct rtable *rt, int create) | 1318 | void rt_bind_peer(struct rtable *rt, int create) |
1312 | { | 1319 | { |
1313 | struct inet_peer *peer; | 1320 | struct inet_peer *peer; |
@@ -1316,6 +1323,8 @@ void rt_bind_peer(struct rtable *rt, int create) | |||
1316 | 1323 | ||
1317 | if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL) | 1324 | if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL) |
1318 | inet_putpeer(peer); | 1325 | inet_putpeer(peer); |
1326 | else | ||
1327 | rt->rt_peer_genid = rt_peer_genid(); | ||
1319 | } | 1328 | } |
1320 | 1329 | ||
1321 | /* | 1330 | /* |
@@ -1767,8 +1776,16 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
1767 | 1776 | ||
1768 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | 1777 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) |
1769 | { | 1778 | { |
1770 | if (rt_is_expired((struct rtable *)dst)) | 1779 | struct rtable *rt = (struct rtable *) dst; |
1780 | |||
1781 | if (rt_is_expired(rt)) | ||
1771 | return NULL; | 1782 | return NULL; |
1783 | if (rt->rt_peer_genid != rt_peer_genid()) { | ||
1784 | if (!rt->peer) | ||
1785 | rt_bind_peer(rt, 0); | ||
1786 | |||
1787 | rt->rt_peer_genid = rt_peer_genid(); | ||
1788 | } | ||
1772 | return dst; | 1789 | return dst; |
1773 | } | 1790 | } |
1774 | 1791 | ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 12ec83d48806..ad8556e6fd41 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -240,6 +240,13 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
240 | } | 240 | } |
241 | } | 241 | } |
242 | 242 | ||
243 | static atomic_t __rt6_peer_genid = ATOMIC_INIT(0); | ||
244 | |||
245 | static u32 rt6_peer_genid(void) | ||
246 | { | ||
247 | return atomic_read(&__rt6_peer_genid); | ||
248 | } | ||
249 | |||
243 | void rt6_bind_peer(struct rt6_info *rt, int create) | 250 | void rt6_bind_peer(struct rt6_info *rt, int create) |
244 | { | 251 | { |
245 | struct inet_peer *peer; | 252 | struct inet_peer *peer; |
@@ -247,6 +254,8 @@ void rt6_bind_peer(struct rt6_info *rt, int create) | |||
247 | peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); | 254 | peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); |
248 | if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) | 255 | if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) |
249 | inet_putpeer(peer); | 256 | inet_putpeer(peer); |
257 | else | ||
258 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
250 | } | 259 | } |
251 | 260 | ||
252 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 261 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
@@ -912,9 +921,14 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) | |||
912 | 921 | ||
913 | rt = (struct rt6_info *) dst; | 922 | rt = (struct rt6_info *) dst; |
914 | 923 | ||
915 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) | 924 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) { |
925 | if (rt->rt6i_peer_genid != rt6_peer_genid()) { | ||
926 | if (!rt->rt6i_peer) | ||
927 | rt6_bind_peer(rt, 0); | ||
928 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
929 | } | ||
916 | return dst; | 930 | return dst; |
917 | 931 | } | |
918 | return NULL; | 932 | return NULL; |
919 | } | 933 | } |
920 | 934 | ||