aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip6_fib.h1
-rw-r--r--include/net/route.h1
-rw-r--r--net/ipv4/route.c19
-rw-r--r--net/ipv6/route.c18
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
1311static atomic_t __rt_peer_genid = ATOMIC_INIT(0);
1312
1313static u32 rt_peer_genid(void)
1314{
1315 return atomic_read(&__rt_peer_genid);
1316}
1317
1311void rt_bind_peer(struct rtable *rt, int create) 1318void 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
1768static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) 1777static 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
243static atomic_t __rt6_peer_genid = ATOMIC_INIT(0);
244
245static u32 rt6_peer_genid(void)
246{
247 return atomic_read(&__rt6_peer_genid);
248}
249
243void rt6_bind_peer(struct rt6_info *rt, int create) 250void 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
252static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 261static 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