aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/inetpeer.h54
-rw-r--r--include/net/ip6_fib.h32
-rw-r--r--include/net/ip6_route.h6
-rw-r--r--include/net/route.h42
-rw-r--r--net/ipv4/route.c56
-rw-r--r--net/ipv4/xfrm4_policy.c10
-rw-r--r--net/ipv6/route.c42
-rw-r--r--net/ipv6/xfrm6_policy.c10
8 files changed, 193 insertions, 59 deletions
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index b84b32fd5df1..d432489e7109 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -71,6 +71,60 @@ struct inet_peer_base {
71 int total; 71 int total;
72}; 72};
73 73
74#define INETPEER_BASE_BIT 0x1UL
75
76static inline struct inet_peer *inetpeer_ptr(unsigned long val)
77{
78 BUG_ON(val & INETPEER_BASE_BIT);
79 return (struct inet_peer *) val;
80}
81
82static inline struct inet_peer_base *inetpeer_base_ptr(unsigned long val)
83{
84 if (!(val & INETPEER_BASE_BIT))
85 return NULL;
86 val &= ~INETPEER_BASE_BIT;
87 return (struct inet_peer_base *) val;
88}
89
90static inline bool inetpeer_ptr_is_peer(unsigned long val)
91{
92 return !(val & INETPEER_BASE_BIT);
93}
94
95static inline void __inetpeer_ptr_set_peer(unsigned long *val, struct inet_peer *peer)
96{
97 /* This implicitly clears INETPEER_BASE_BIT */
98 *val = (unsigned long) peer;
99}
100
101static inline bool inetpeer_ptr_set_peer(unsigned long *ptr, struct inet_peer *peer)
102{
103 unsigned long val = (unsigned long) peer;
104 unsigned long orig = *ptr;
105
106 if (!(orig & INETPEER_BASE_BIT) || !val ||
107 cmpxchg(ptr, orig, val) != orig)
108 return false;
109 return true;
110}
111
112static inline void inetpeer_init_ptr(unsigned long *ptr, struct inet_peer_base *base)
113{
114 *ptr = (unsigned long) base | INETPEER_BASE_BIT;
115}
116
117static inline void inetpeer_transfer_peer(unsigned long *to, unsigned long *from)
118{
119 unsigned long val = *from;
120
121 *to = val;
122 if (inetpeer_ptr_is_peer(val)) {
123 struct inet_peer *peer = inetpeer_ptr(val);
124 atomic_inc(&peer->refcnt);
125 }
126}
127
74extern void inet_peer_base_init(struct inet_peer_base *); 128extern void inet_peer_base_init(struct inet_peer_base *);
75 129
76void inet_initpeers(void) __init; 130void inet_initpeers(void) __init;
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 0ae759a6c76e..3ac5f155c690 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -107,7 +107,7 @@ struct rt6_info {
107 u32 rt6i_peer_genid; 107 u32 rt6i_peer_genid;
108 108
109 struct inet6_dev *rt6i_idev; 109 struct inet6_dev *rt6i_idev;
110 struct inet_peer *rt6i_peer; 110 unsigned long _rt6i_peer;
111 111
112#ifdef CONFIG_XFRM 112#ifdef CONFIG_XFRM
113 u32 rt6i_flow_cache_genid; 113 u32 rt6i_flow_cache_genid;
@@ -118,6 +118,36 @@ struct rt6_info {
118 u8 rt6i_protocol; 118 u8 rt6i_protocol;
119}; 119};
120 120
121static inline struct inet_peer *rt6_peer_ptr(struct rt6_info *rt)
122{
123 return inetpeer_ptr(rt->_rt6i_peer);
124}
125
126static inline bool rt6_has_peer(struct rt6_info *rt)
127{
128 return inetpeer_ptr_is_peer(rt->_rt6i_peer);
129}
130
131static inline void __rt6_set_peer(struct rt6_info *rt, struct inet_peer *peer)
132{
133 __inetpeer_ptr_set_peer(&rt->_rt6i_peer, peer);
134}
135
136static inline bool rt6_set_peer(struct rt6_info *rt, struct inet_peer *peer)
137{
138 return inetpeer_ptr_set_peer(&rt->_rt6i_peer, peer);
139}
140
141static inline void rt6_init_peer(struct rt6_info *rt, struct inet_peer_base *base)
142{
143 inetpeer_init_ptr(&rt->_rt6i_peer, base);
144}
145
146static inline void rt6_transfer_peer(struct rt6_info *rt, struct rt6_info *ort)
147{
148 inetpeer_transfer_peer(&rt->_rt6i_peer, &ort->_rt6i_peer);
149}
150
121static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) 151static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
122{ 152{
123 return ((struct rt6_info *)dst)->rt6i_idev; 153 return ((struct rt6_info *)dst)->rt6i_idev;
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 73d750288121..f88a85cf31c3 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -57,11 +57,11 @@ extern void rt6_bind_peer(struct rt6_info *rt, int create);
57 57
58static inline struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create) 58static inline struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create)
59{ 59{
60 if (rt->rt6i_peer) 60 if (rt6_has_peer(rt))
61 return rt->rt6i_peer; 61 return rt6_peer_ptr(rt);
62 62
63 rt6_bind_peer(rt, create); 63 rt6_bind_peer(rt, create);
64 return rt->rt6i_peer; 64 return rt6_peer_ptr(rt);
65} 65}
66 66
67static inline struct inet_peer *rt6_get_peer(struct rt6_info *rt) 67static inline struct inet_peer *rt6_get_peer(struct rt6_info *rt)
diff --git a/include/net/route.h b/include/net/route.h
index 433fc6c1d404..6340c37677fc 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -67,10 +67,44 @@ struct rtable {
67 /* Miscellaneous cached information */ 67 /* Miscellaneous cached information */
68 __be32 rt_spec_dst; /* RFC1122 specific destination */ 68 __be32 rt_spec_dst; /* RFC1122 specific destination */
69 u32 rt_peer_genid; 69 u32 rt_peer_genid;
70 struct inet_peer *peer; /* long-living peer info */ 70 unsigned long _peer; /* long-living peer info */
71 struct fib_info *fi; /* for client ref to shared metrics */ 71 struct fib_info *fi; /* for client ref to shared metrics */
72}; 72};
73 73
74static inline struct inet_peer *rt_peer_ptr(struct rtable *rt)
75{
76 return inetpeer_ptr(rt->_peer);
77}
78
79static inline bool rt_has_peer(struct rtable *rt)
80{
81 return inetpeer_ptr_is_peer(rt->_peer);
82}
83
84static inline void __rt_set_peer(struct rtable *rt, struct inet_peer *peer)
85{
86 __inetpeer_ptr_set_peer(&rt->_peer, peer);
87}
88
89static inline bool rt_set_peer(struct rtable *rt, struct inet_peer *peer)
90{
91 return inetpeer_ptr_set_peer(&rt->_peer, peer);
92}
93
94static inline void rt_init_peer(struct rtable *rt, struct inet_peer_base *base)
95{
96 inetpeer_init_ptr(&rt->_peer, base);
97}
98
99static inline void rt_transfer_peer(struct rtable *rt, struct rtable *ort)
100{
101 rt->_peer = ort->_peer;
102 if (rt_has_peer(ort)) {
103 struct inet_peer *peer = rt_peer_ptr(ort);
104 atomic_inc(&peer->refcnt);
105 }
106}
107
74static inline bool rt_is_input_route(const struct rtable *rt) 108static inline bool rt_is_input_route(const struct rtable *rt)
75{ 109{
76 return rt->rt_route_iif != 0; 110 return rt->rt_route_iif != 0;
@@ -298,11 +332,11 @@ extern void rt_bind_peer(struct rtable *rt, __be32 daddr, int create);
298 332
299static inline struct inet_peer *__rt_get_peer(struct rtable *rt, __be32 daddr, int create) 333static inline struct inet_peer *__rt_get_peer(struct rtable *rt, __be32 daddr, int create)
300{ 334{
301 if (rt->peer) 335 if (rt_has_peer(rt))
302 return rt->peer; 336 return rt_peer_ptr(rt);
303 337
304 rt_bind_peer(rt, daddr, create); 338 rt_bind_peer(rt, daddr, create);
305 return rt->peer; 339 return rt_peer_ptr(rt);
306} 340}
307 341
308static inline struct inet_peer *rt_get_peer(struct rtable *rt, __be32 daddr) 342static inline struct inet_peer *rt_get_peer(struct rtable *rt, __be32 daddr)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 2aa663a6ae9e..03e5b614370e 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -677,7 +677,7 @@ static inline int rt_fast_clean(struct rtable *rth)
677static inline int rt_valuable(struct rtable *rth) 677static inline int rt_valuable(struct rtable *rth)
678{ 678{
679 return (rth->rt_flags & (RTCF_REDIRECTED | RTCF_NOTIFY)) || 679 return (rth->rt_flags & (RTCF_REDIRECTED | RTCF_NOTIFY)) ||
680 (rth->peer && rth->peer->pmtu_expires); 680 (rt_has_peer(rth) && rt_peer_ptr(rth)->pmtu_expires);
681} 681}
682 682
683static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2) 683static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2)
@@ -1325,12 +1325,16 @@ static u32 rt_peer_genid(void)
1325 1325
1326void rt_bind_peer(struct rtable *rt, __be32 daddr, int create) 1326void rt_bind_peer(struct rtable *rt, __be32 daddr, int create)
1327{ 1327{
1328 struct net *net = dev_net(rt->dst.dev); 1328 struct inet_peer_base *base;
1329 struct inet_peer *peer; 1329 struct inet_peer *peer;
1330 1330
1331 peer = inet_getpeer_v4(net->ipv4.peers, daddr, create); 1331 base = inetpeer_base_ptr(rt->_peer);
1332 if (!base)
1333 return;
1334
1335 peer = inet_getpeer_v4(base, daddr, create);
1332 1336
1333 if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL) 1337 if (!rt_set_peer(rt, peer))
1334 inet_putpeer(peer); 1338 inet_putpeer(peer);
1335 else 1339 else
1336 rt->rt_peer_genid = rt_peer_genid(); 1340 rt->rt_peer_genid = rt_peer_genid();
@@ -1533,8 +1537,10 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
1533 rt_genid(dev_net(dst->dev))); 1537 rt_genid(dev_net(dst->dev)));
1534 rt_del(hash, rt); 1538 rt_del(hash, rt);
1535 ret = NULL; 1539 ret = NULL;
1536 } else if (rt->peer && peer_pmtu_expired(rt->peer)) { 1540 } else if (rt_has_peer(rt)) {
1537 dst_metric_set(dst, RTAX_MTU, rt->peer->pmtu_orig); 1541 struct inet_peer *peer = rt_peer_ptr(rt);
1542 if (peer_pmtu_expired(peer))
1543 dst_metric_set(dst, RTAX_MTU, peer->pmtu_orig);
1538 } 1544 }
1539 } 1545 }
1540 return ret; 1546 return ret;
@@ -1796,14 +1802,13 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
1796static void ipv4_dst_destroy(struct dst_entry *dst) 1802static void ipv4_dst_destroy(struct dst_entry *dst)
1797{ 1803{
1798 struct rtable *rt = (struct rtable *) dst; 1804 struct rtable *rt = (struct rtable *) dst;
1799 struct inet_peer *peer = rt->peer;
1800 1805
1801 if (rt->fi) { 1806 if (rt->fi) {
1802 fib_info_put(rt->fi); 1807 fib_info_put(rt->fi);
1803 rt->fi = NULL; 1808 rt->fi = NULL;
1804 } 1809 }
1805 if (peer) { 1810 if (rt_has_peer(rt)) {
1806 rt->peer = NULL; 1811 struct inet_peer *peer = rt_peer_ptr(rt);
1807 inet_putpeer(peer); 1812 inet_putpeer(peer);
1808 } 1813 }
1809} 1814}
@@ -1816,8 +1821,11 @@ static void ipv4_link_failure(struct sk_buff *skb)
1816 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); 1821 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
1817 1822
1818 rt = skb_rtable(skb); 1823 rt = skb_rtable(skb);
1819 if (rt && rt->peer && peer_pmtu_cleaned(rt->peer)) 1824 if (rt && rt_has_peer(rt)) {
1820 dst_metric_set(&rt->dst, RTAX_MTU, rt->peer->pmtu_orig); 1825 struct inet_peer *peer = rt_peer_ptr(rt);
1826 if (peer_pmtu_cleaned(peer))
1827 dst_metric_set(&rt->dst, RTAX_MTU, peer->pmtu_orig);
1828 }
1821} 1829}
1822 1830
1823static int ip_rt_bug(struct sk_buff *skb) 1831static int ip_rt_bug(struct sk_buff *skb)
@@ -1919,7 +1927,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
1919static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4, 1927static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
1920 struct fib_info *fi) 1928 struct fib_info *fi)
1921{ 1929{
1922 struct net *net = dev_net(rt->dst.dev); 1930 struct inet_peer_base *base;
1923 struct inet_peer *peer; 1931 struct inet_peer *peer;
1924 int create = 0; 1932 int create = 0;
1925 1933
@@ -1929,8 +1937,12 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
1929 if (fl4 && (fl4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS)) 1937 if (fl4 && (fl4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS))
1930 create = 1; 1938 create = 1;
1931 1939
1932 rt->peer = peer = inet_getpeer_v4(net->ipv4.peers, rt->rt_dst, create); 1940 base = inetpeer_base_ptr(rt->_peer);
1941 BUG_ON(!base);
1942
1943 peer = inet_getpeer_v4(base, rt->rt_dst, create);
1933 if (peer) { 1944 if (peer) {
1945 __rt_set_peer(rt, peer);
1934 rt->rt_peer_genid = rt_peer_genid(); 1946 rt->rt_peer_genid = rt_peer_genid();
1935 if (inet_metrics_new(peer)) 1947 if (inet_metrics_new(peer))
1936 memcpy(peer->metrics, fi->fib_metrics, 1948 memcpy(peer->metrics, fi->fib_metrics,
@@ -2046,7 +2058,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
2046 rth->rt_gateway = daddr; 2058 rth->rt_gateway = daddr;
2047 rth->rt_spec_dst= spec_dst; 2059 rth->rt_spec_dst= spec_dst;
2048 rth->rt_peer_genid = 0; 2060 rth->rt_peer_genid = 0;
2049 rth->peer = NULL; 2061 rt_init_peer(rth, dev_net(dev)->ipv4.peers);
2050 rth->fi = NULL; 2062 rth->fi = NULL;
2051 if (our) { 2063 if (our) {
2052 rth->dst.input= ip_local_deliver; 2064 rth->dst.input= ip_local_deliver;
@@ -2174,7 +2186,7 @@ static int __mkroute_input(struct sk_buff *skb,
2174 rth->rt_gateway = daddr; 2186 rth->rt_gateway = daddr;
2175 rth->rt_spec_dst= spec_dst; 2187 rth->rt_spec_dst= spec_dst;
2176 rth->rt_peer_genid = 0; 2188 rth->rt_peer_genid = 0;
2177 rth->peer = NULL; 2189 rt_init_peer(rth, dev_net(rth->dst.dev)->ipv4.peers);
2178 rth->fi = NULL; 2190 rth->fi = NULL;
2179 2191
2180 rth->dst.input = ip_forward; 2192 rth->dst.input = ip_forward;
@@ -2357,7 +2369,7 @@ local_input:
2357 rth->rt_gateway = daddr; 2369 rth->rt_gateway = daddr;
2358 rth->rt_spec_dst= spec_dst; 2370 rth->rt_spec_dst= spec_dst;
2359 rth->rt_peer_genid = 0; 2371 rth->rt_peer_genid = 0;
2360 rth->peer = NULL; 2372 rt_init_peer(rth, net->ipv4.peers);
2361 rth->fi = NULL; 2373 rth->fi = NULL;
2362 if (res.type == RTN_UNREACHABLE) { 2374 if (res.type == RTN_UNREACHABLE) {
2363 rth->dst.input= ip_error; 2375 rth->dst.input= ip_error;
@@ -2561,7 +2573,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
2561 rth->rt_gateway = fl4->daddr; 2573 rth->rt_gateway = fl4->daddr;
2562 rth->rt_spec_dst= fl4->saddr; 2574 rth->rt_spec_dst= fl4->saddr;
2563 rth->rt_peer_genid = 0; 2575 rth->rt_peer_genid = 0;
2564 rth->peer = NULL; 2576 rt_init_peer(rth, dev_net(dev_out)->ipv4.peers);
2565 rth->fi = NULL; 2577 rth->fi = NULL;
2566 2578
2567 RT_CACHE_STAT_INC(out_slow_tot); 2579 RT_CACHE_STAT_INC(out_slow_tot);
@@ -2898,9 +2910,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
2898 rt->rt_src = ort->rt_src; 2910 rt->rt_src = ort->rt_src;
2899 rt->rt_gateway = ort->rt_gateway; 2911 rt->rt_gateway = ort->rt_gateway;
2900 rt->rt_spec_dst = ort->rt_spec_dst; 2912 rt->rt_spec_dst = ort->rt_spec_dst;
2901 rt->peer = ort->peer; 2913 rt_transfer_peer(rt, ort);
2902 if (rt->peer)
2903 atomic_inc(&rt->peer->refcnt);
2904 rt->fi = ort->fi; 2914 rt->fi = ort->fi;
2905 if (rt->fi) 2915 if (rt->fi)
2906 atomic_inc(&rt->fi->fib_clntref); 2916 atomic_inc(&rt->fi->fib_clntref);
@@ -2938,7 +2948,6 @@ static int rt_fill_info(struct net *net,
2938 struct rtmsg *r; 2948 struct rtmsg *r;
2939 struct nlmsghdr *nlh; 2949 struct nlmsghdr *nlh;
2940 unsigned long expires = 0; 2950 unsigned long expires = 0;
2941 const struct inet_peer *peer = rt->peer;
2942 u32 id = 0, ts = 0, tsage = 0, error; 2951 u32 id = 0, ts = 0, tsage = 0, error;
2943 2952
2944 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags); 2953 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
@@ -2994,8 +3003,9 @@ static int rt_fill_info(struct net *net,
2994 goto nla_put_failure; 3003 goto nla_put_failure;
2995 3004
2996 error = rt->dst.error; 3005 error = rt->dst.error;
2997 if (peer) { 3006 if (rt_has_peer(rt)) {
2998 inet_peer_refcheck(rt->peer); 3007 const struct inet_peer *peer = rt_peer_ptr(rt);
3008 inet_peer_refcheck(peer);
2999 id = atomic_read(&peer->ip_id_count) & 0xffff; 3009 id = atomic_read(&peer->ip_id_count) & 0xffff;
3000 if (peer->tcp_ts_stamp) { 3010 if (peer->tcp_ts_stamp) {
3001 ts = peer->tcp_ts; 3011 ts = peer->tcp_ts;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 0d3426cb5c4f..8855d8268552 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -90,9 +90,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
90 xdst->u.dst.dev = dev; 90 xdst->u.dst.dev = dev;
91 dev_hold(dev); 91 dev_hold(dev);
92 92
93 xdst->u.rt.peer = rt->peer; 93 rt_transfer_peer(&xdst->u.rt, rt);
94 if (rt->peer)
95 atomic_inc(&rt->peer->refcnt);
96 94
97 /* Sheit... I remember I did this right. Apparently, 95 /* Sheit... I remember I did this right. Apparently,
98 * it was magically lost, so this code needs audit */ 96 * it was magically lost, so this code needs audit */
@@ -212,8 +210,10 @@ static void xfrm4_dst_destroy(struct dst_entry *dst)
212 210
213 dst_destroy_metrics_generic(dst); 211 dst_destroy_metrics_generic(dst);
214 212
215 if (likely(xdst->u.rt.peer)) 213 if (rt_has_peer(&xdst->u.rt)) {
216 inet_putpeer(xdst->u.rt.peer); 214 struct inet_peer *peer = rt_peer_ptr(&xdst->u.rt);
215 inet_putpeer(peer);
216 }
217 217
218 xfrm_dst_destroy(xdst); 218 xfrm_dst_destroy(xdst);
219} 219}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8fc41d502bbd..17a9b8687f29 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -258,16 +258,18 @@ static struct rt6_info ip6_blk_hole_entry_template = {
258#endif 258#endif
259 259
260/* allocate dst with ip6_dst_ops */ 260/* allocate dst with ip6_dst_ops */
261static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops, 261static inline struct rt6_info *ip6_dst_alloc(struct net *net,
262 struct net_device *dev, 262 struct net_device *dev,
263 int flags) 263 int flags)
264{ 264{
265 struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, flags); 265 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
266 0, 0, flags);
266 267
267 if (rt) 268 if (rt) {
268 memset(&rt->rt6i_table, 0, 269 memset(&rt->rt6i_table, 0,
269 sizeof(*rt) - sizeof(struct dst_entry)); 270 sizeof(*rt) - sizeof(struct dst_entry));
270 271 rt6_init_peer(rt, net->ipv6.peers);
272 }
271 return rt; 273 return rt;
272} 274}
273 275
@@ -275,7 +277,6 @@ static void ip6_dst_destroy(struct dst_entry *dst)
275{ 277{
276 struct rt6_info *rt = (struct rt6_info *)dst; 278 struct rt6_info *rt = (struct rt6_info *)dst;
277 struct inet6_dev *idev = rt->rt6i_idev; 279 struct inet6_dev *idev = rt->rt6i_idev;
278 struct inet_peer *peer = rt->rt6i_peer;
279 280
280 if (!(rt->dst.flags & DST_HOST)) 281 if (!(rt->dst.flags & DST_HOST))
281 dst_destroy_metrics_generic(dst); 282 dst_destroy_metrics_generic(dst);
@@ -288,8 +289,8 @@ static void ip6_dst_destroy(struct dst_entry *dst)
288 if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from) 289 if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from)
289 dst_release(dst->from); 290 dst_release(dst->from);
290 291
291 if (peer) { 292 if (rt6_has_peer(rt)) {
292 rt->rt6i_peer = NULL; 293 struct inet_peer *peer = rt6_peer_ptr(rt);
293 inet_putpeer(peer); 294 inet_putpeer(peer);
294 } 295 }
295} 296}
@@ -303,11 +304,15 @@ static u32 rt6_peer_genid(void)
303 304
304void rt6_bind_peer(struct rt6_info *rt, int create) 305void rt6_bind_peer(struct rt6_info *rt, int create)
305{ 306{
306 struct net *net = dev_net(rt->dst.dev); 307 struct inet_peer_base *base;
307 struct inet_peer *peer; 308 struct inet_peer *peer;
308 309
309 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, create); 310 base = inetpeer_base_ptr(rt->_rt6i_peer);
310 if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) 311 if (!base)
312 return;
313
314 peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create);
315 if (!rt6_set_peer(rt, peer))
311 inet_putpeer(peer); 316 inet_putpeer(peer);
312 else 317 else
313 rt->rt6i_peer_genid = rt6_peer_genid(); 318 rt->rt6i_peer_genid = rt6_peer_genid();
@@ -950,6 +955,7 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
950 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0); 955 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0);
951 if (rt) { 956 if (rt) {
952 memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry)); 957 memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry));
958 rt6_init_peer(rt, net->ipv6.peers);
953 959
954 new = &rt->dst; 960 new = &rt->dst;
955 961
@@ -994,7 +1000,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
994 1000
995 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) { 1001 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) {
996 if (rt->rt6i_peer_genid != rt6_peer_genid()) { 1002 if (rt->rt6i_peer_genid != rt6_peer_genid()) {
997 if (!rt->rt6i_peer) 1003 if (!rt6_has_peer(rt))
998 rt6_bind_peer(rt, 0); 1004 rt6_bind_peer(rt, 0);
999 rt->rt6i_peer_genid = rt6_peer_genid(); 1005 rt->rt6i_peer_genid = rt6_peer_genid();
1000 } 1006 }
@@ -1108,7 +1114,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
1108 if (unlikely(!idev)) 1114 if (unlikely(!idev))
1109 return ERR_PTR(-ENODEV); 1115 return ERR_PTR(-ENODEV);
1110 1116
1111 rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0); 1117 rt = ip6_dst_alloc(net, dev, 0);
1112 if (unlikely(!rt)) { 1118 if (unlikely(!rt)) {
1113 in6_dev_put(idev); 1119 in6_dev_put(idev);
1114 dst = ERR_PTR(-ENOMEM); 1120 dst = ERR_PTR(-ENOMEM);
@@ -1290,7 +1296,7 @@ int ip6_route_add(struct fib6_config *cfg)
1290 if (!table) 1296 if (!table)
1291 goto out; 1297 goto out;
1292 1298
1293 rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL, DST_NOCOUNT); 1299 rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT);
1294 1300
1295 if (!rt) { 1301 if (!rt) {
1296 err = -ENOMEM; 1302 err = -ENOMEM;
@@ -1812,8 +1818,7 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
1812 const struct in6_addr *dest) 1818 const struct in6_addr *dest)
1813{ 1819{
1814 struct net *net = dev_net(ort->dst.dev); 1820 struct net *net = dev_net(ort->dst.dev);
1815 struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, 1821 struct rt6_info *rt = ip6_dst_alloc(net, ort->dst.dev, 0);
1816 ort->dst.dev, 0);
1817 1822
1818 if (rt) { 1823 if (rt) {
1819 rt->dst.input = ort->dst.input; 1824 rt->dst.input = ort->dst.input;
@@ -2097,8 +2102,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2097 bool anycast) 2102 bool anycast)
2098{ 2103{
2099 struct net *net = dev_net(idev->dev); 2104 struct net *net = dev_net(idev->dev);
2100 struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, 2105 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0);
2101 net->loopback_dev, 0);
2102 int err; 2106 int err;
2103 2107
2104 if (!rt) { 2108 if (!rt) {
@@ -2519,7 +2523,9 @@ static int rt6_fill_node(struct net *net,
2519 else 2523 else
2520 expires = INT_MAX; 2524 expires = INT_MAX;
2521 2525
2522 peer = rt->rt6i_peer; 2526 peer = NULL;
2527 if (rt6_has_peer(rt))
2528 peer = rt6_peer_ptr(rt);
2523 ts = tsage = 0; 2529 ts = tsage = 0;
2524 if (peer && peer->tcp_ts_stamp) { 2530 if (peer && peer->tcp_ts_stamp) {
2525 ts = peer->tcp_ts; 2531 ts = peer->tcp_ts;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 8625fba96db9..d7494845efbf 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -99,9 +99,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
99 if (!xdst->u.rt6.rt6i_idev) 99 if (!xdst->u.rt6.rt6i_idev)
100 return -ENODEV; 100 return -ENODEV;
101 101
102 xdst->u.rt6.rt6i_peer = rt->rt6i_peer; 102 rt6_transfer_peer(&xdst->u.rt6, rt);
103 if (rt->rt6i_peer)
104 atomic_inc(&rt->rt6i_peer->refcnt);
105 103
106 /* Sheit... I remember I did this right. Apparently, 104 /* Sheit... I remember I did this right. Apparently,
107 * it was magically lost, so this code needs audit */ 105 * it was magically lost, so this code needs audit */
@@ -223,8 +221,10 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
223 if (likely(xdst->u.rt6.rt6i_idev)) 221 if (likely(xdst->u.rt6.rt6i_idev))
224 in6_dev_put(xdst->u.rt6.rt6i_idev); 222 in6_dev_put(xdst->u.rt6.rt6i_idev);
225 dst_destroy_metrics_generic(dst); 223 dst_destroy_metrics_generic(dst);
226 if (likely(xdst->u.rt6.rt6i_peer)) 224 if (rt6_has_peer(&xdst->u.rt6)) {
227 inet_putpeer(xdst->u.rt6.rt6i_peer); 225 struct inet_peer *peer = rt6_peer_ptr(&xdst->u.rt6);
226 inet_putpeer(peer);
227 }
228 xfrm_dst_destroy(xdst); 228 xfrm_dst_destroy(xdst);
229} 229}
230 230