diff options
-rw-r--r-- | include/net/inetpeer.h | 54 | ||||
-rw-r--r-- | include/net/ip6_fib.h | 32 | ||||
-rw-r--r-- | include/net/ip6_route.h | 6 | ||||
-rw-r--r-- | include/net/route.h | 42 | ||||
-rw-r--r-- | net/ipv4/route.c | 56 | ||||
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 10 | ||||
-rw-r--r-- | net/ipv6/route.c | 42 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 10 |
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 | |||
76 | static 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 | |||
82 | static 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 | |||
90 | static inline bool inetpeer_ptr_is_peer(unsigned long val) | ||
91 | { | ||
92 | return !(val & INETPEER_BASE_BIT); | ||
93 | } | ||
94 | |||
95 | static 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 | |||
101 | static 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 | |||
112 | static inline void inetpeer_init_ptr(unsigned long *ptr, struct inet_peer_base *base) | ||
113 | { | ||
114 | *ptr = (unsigned long) base | INETPEER_BASE_BIT; | ||
115 | } | ||
116 | |||
117 | static 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 | |||
74 | extern void inet_peer_base_init(struct inet_peer_base *); | 128 | extern void inet_peer_base_init(struct inet_peer_base *); |
75 | 129 | ||
76 | void inet_initpeers(void) __init; | 130 | void 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 | ||
121 | static inline struct inet_peer *rt6_peer_ptr(struct rt6_info *rt) | ||
122 | { | ||
123 | return inetpeer_ptr(rt->_rt6i_peer); | ||
124 | } | ||
125 | |||
126 | static inline bool rt6_has_peer(struct rt6_info *rt) | ||
127 | { | ||
128 | return inetpeer_ptr_is_peer(rt->_rt6i_peer); | ||
129 | } | ||
130 | |||
131 | static 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 | |||
136 | static 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 | |||
141 | static 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 | |||
146 | static 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 | |||
121 | static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) | 151 | static 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 | ||
58 | static inline struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create) | 58 | static 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 | ||
67 | static inline struct inet_peer *rt6_get_peer(struct rt6_info *rt) | 67 | static 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 | ||
74 | static inline struct inet_peer *rt_peer_ptr(struct rtable *rt) | ||
75 | { | ||
76 | return inetpeer_ptr(rt->_peer); | ||
77 | } | ||
78 | |||
79 | static inline bool rt_has_peer(struct rtable *rt) | ||
80 | { | ||
81 | return inetpeer_ptr_is_peer(rt->_peer); | ||
82 | } | ||
83 | |||
84 | static inline void __rt_set_peer(struct rtable *rt, struct inet_peer *peer) | ||
85 | { | ||
86 | __inetpeer_ptr_set_peer(&rt->_peer, peer); | ||
87 | } | ||
88 | |||
89 | static inline bool rt_set_peer(struct rtable *rt, struct inet_peer *peer) | ||
90 | { | ||
91 | return inetpeer_ptr_set_peer(&rt->_peer, peer); | ||
92 | } | ||
93 | |||
94 | static inline void rt_init_peer(struct rtable *rt, struct inet_peer_base *base) | ||
95 | { | ||
96 | inetpeer_init_ptr(&rt->_peer, base); | ||
97 | } | ||
98 | |||
99 | static 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 | |||
74 | static inline bool rt_is_input_route(const struct rtable *rt) | 108 | static 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 | ||
299 | static inline struct inet_peer *__rt_get_peer(struct rtable *rt, __be32 daddr, int create) | 333 | static 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 | ||
308 | static inline struct inet_peer *rt_get_peer(struct rtable *rt, __be32 daddr) | 342 | static 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) | |||
677 | static inline int rt_valuable(struct rtable *rth) | 677 | static 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 | ||
683 | static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2) | 683 | static 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 | ||
1326 | void rt_bind_peer(struct rtable *rt, __be32 daddr, int create) | 1326 | void 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) | |||
1796 | static void ipv4_dst_destroy(struct dst_entry *dst) | 1802 | static 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 | ||
1823 | static int ip_rt_bug(struct sk_buff *skb) | 1831 | static int ip_rt_bug(struct sk_buff *skb) |
@@ -1919,7 +1927,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst) | |||
1919 | static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4, | 1927 | static 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 */ |
261 | static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops, | 261 | static 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 | ||
304 | void rt6_bind_peer(struct rt6_info *rt, int create) | 305 | void 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 | ||