Skip to content

Commit 97bab73

Browse files
committed
inet: Hide route peer accesses behind helpers.
We encode the pointer(s) into an unsigned long with one state bit. The state bit is used so we can store the inetpeer tree root to use when resolving the peer later. Later the peer roots will be per-FIB table, and this change works to facilitate that. Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent c0efc88 commit 97bab73

File tree

8 files changed

+193
-59
lines changed

8 files changed

+193
-59
lines changed

include/net/inetpeer.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,60 @@ struct inet_peer_base {
7171
int total;
7272
};
7373

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+
74128
extern void inet_peer_base_init(struct inet_peer_base *);
75129

76130
void inet_initpeers(void) __init;

include/net/ip6_fib.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ struct rt6_info {
107107
u32 rt6i_peer_genid;
108108

109109
struct inet6_dev *rt6i_idev;
110-
struct inet_peer *rt6i_peer;
110+
unsigned long _rt6i_peer;
111111

112112
#ifdef CONFIG_XFRM
113113
u32 rt6i_flow_cache_genid;
@@ -118,6 +118,36 @@ struct rt6_info {
118118
u8 rt6i_protocol;
119119
};
120120

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+
121151
static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
122152
{
123153
return ((struct rt6_info *)dst)->rt6i_idev;

include/net/ip6_route.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ extern void rt6_bind_peer(struct rt6_info *rt, int create);
5757

5858
static inline struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create)
5959
{
60-
if (rt->rt6i_peer)
61-
return rt->rt6i_peer;
60+
if (rt6_has_peer(rt))
61+
return rt6_peer_ptr(rt);
6262

6363
rt6_bind_peer(rt, create);
64-
return rt->rt6i_peer;
64+
return rt6_peer_ptr(rt);
6565
}
6666

6767
static inline struct inet_peer *rt6_get_peer(struct rt6_info *rt)

include/net/route.h

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,44 @@ struct rtable {
6767
/* Miscellaneous cached information */
6868
__be32 rt_spec_dst; /* RFC1122 specific destination */
6969
u32 rt_peer_genid;
70-
struct inet_peer *peer; /* long-living peer info */
70+
unsigned long _peer; /* long-living peer info */
7171
struct fib_info *fi; /* for client ref to shared metrics */
7272
};
7373

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+
74108
static inline bool rt_is_input_route(const struct rtable *rt)
75109
{
76110
return rt->rt_route_iif != 0;
@@ -298,11 +332,11 @@ extern void rt_bind_peer(struct rtable *rt, __be32 daddr, int create);
298332

299333
static inline struct inet_peer *__rt_get_peer(struct rtable *rt, __be32 daddr, int create)
300334
{
301-
if (rt->peer)
302-
return rt->peer;
335+
if (rt_has_peer(rt))
336+
return rt_peer_ptr(rt);
303337

304338
rt_bind_peer(rt, daddr, create);
305-
return rt->peer;
339+
return rt_peer_ptr(rt);
306340
}
307341

308342
static inline struct inet_peer *rt_get_peer(struct rtable *rt, __be32 daddr)

net/ipv4/route.c

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ static inline int rt_fast_clean(struct rtable *rth)
677677
static inline int rt_valuable(struct rtable *rth)
678678
{
679679
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);
681681
}
682682

683683
static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2)
@@ -1325,12 +1325,16 @@ static u32 rt_peer_genid(void)
13251325

13261326
void rt_bind_peer(struct rtable *rt, __be32 daddr, int create)
13271327
{
1328-
struct net *net = dev_net(rt->dst.dev);
1328+
struct inet_peer_base *base;
13291329
struct inet_peer *peer;
13301330

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);
13321336

1333-
if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL)
1337+
if (!rt_set_peer(rt, peer))
13341338
inet_putpeer(peer);
13351339
else
13361340
rt->rt_peer_genid = rt_peer_genid();
@@ -1533,8 +1537,10 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
15331537
rt_genid(dev_net(dst->dev)));
15341538
rt_del(hash, rt);
15351539
ret = NULL;
1536-
} else if (rt->peer && peer_pmtu_expired(rt->peer)) {
1537-
dst_metric_set(dst, RTAX_MTU, rt->peer->pmtu_orig);
1540+
} else if (rt_has_peer(rt)) {
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);
15381544
}
15391545
}
15401546
return ret;
@@ -1796,14 +1802,13 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
17961802
static void ipv4_dst_destroy(struct dst_entry *dst)
17971803
{
17981804
struct rtable *rt = (struct rtable *) dst;
1799-
struct inet_peer *peer = rt->peer;
18001805

18011806
if (rt->fi) {
18021807
fib_info_put(rt->fi);
18031808
rt->fi = NULL;
18041809
}
1805-
if (peer) {
1806-
rt->peer = NULL;
1810+
if (rt_has_peer(rt)) {
1811+
struct inet_peer *peer = rt_peer_ptr(rt);
18071812
inet_putpeer(peer);
18081813
}
18091814
}
@@ -1816,8 +1821,11 @@ static void ipv4_link_failure(struct sk_buff *skb)
18161821
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
18171822

18181823
rt = skb_rtable(skb);
1819-
if (rt && rt->peer && peer_pmtu_cleaned(rt->peer))
1820-
dst_metric_set(&rt->dst, RTAX_MTU, rt->peer->pmtu_orig);
1824+
if (rt && rt_has_peer(rt)) {
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+
}
18211829
}
18221830

18231831
static int ip_rt_bug(struct sk_buff *skb)
@@ -1919,7 +1927,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
19191927
static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
19201928
struct fib_info *fi)
19211929
{
1922-
struct net *net = dev_net(rt->dst.dev);
1930+
struct inet_peer_base *base;
19231931
struct inet_peer *peer;
19241932
int create = 0;
19251933

@@ -1929,8 +1937,12 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
19291937
if (fl4 && (fl4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS))
19301938
create = 1;
19311939

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);
19331944
if (peer) {
1945+
__rt_set_peer(rt, peer);
19341946
rt->rt_peer_genid = rt_peer_genid();
19351947
if (inet_metrics_new(peer))
19361948
memcpy(peer->metrics, fi->fib_metrics,
@@ -2046,7 +2058,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
20462058
rth->rt_gateway = daddr;
20472059
rth->rt_spec_dst= spec_dst;
20482060
rth->rt_peer_genid = 0;
2049-
rth->peer = NULL;
2061+
rt_init_peer(rth, dev_net(dev)->ipv4.peers);
20502062
rth->fi = NULL;
20512063
if (our) {
20522064
rth->dst.input= ip_local_deliver;
@@ -2174,7 +2186,7 @@ static int __mkroute_input(struct sk_buff *skb,
21742186
rth->rt_gateway = daddr;
21752187
rth->rt_spec_dst= spec_dst;
21762188
rth->rt_peer_genid = 0;
2177-
rth->peer = NULL;
2189+
rt_init_peer(rth, dev_net(rth->dst.dev)->ipv4.peers);
21782190
rth->fi = NULL;
21792191

21802192
rth->dst.input = ip_forward;
@@ -2357,7 +2369,7 @@ out: return err;
23572369
rth->rt_gateway = daddr;
23582370
rth->rt_spec_dst= spec_dst;
23592371
rth->rt_peer_genid = 0;
2360-
rth->peer = NULL;
2372+
rt_init_peer(rth, net->ipv4.peers);
23612373
rth->fi = NULL;
23622374
if (res.type == RTN_UNREACHABLE) {
23632375
rth->dst.input= ip_error;
@@ -2561,7 +2573,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
25612573
rth->rt_gateway = fl4->daddr;
25622574
rth->rt_spec_dst= fl4->saddr;
25632575
rth->rt_peer_genid = 0;
2564-
rth->peer = NULL;
2576+
rt_init_peer(rth, dev_net(dev_out)->ipv4.peers);
25652577
rth->fi = NULL;
25662578

25672579
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
28982910
rt->rt_src = ort->rt_src;
28992911
rt->rt_gateway = ort->rt_gateway;
29002912
rt->rt_spec_dst = ort->rt_spec_dst;
2901-
rt->peer = ort->peer;
2902-
if (rt->peer)
2903-
atomic_inc(&rt->peer->refcnt);
2913+
rt_transfer_peer(rt, ort);
29042914
rt->fi = ort->fi;
29052915
if (rt->fi)
29062916
atomic_inc(&rt->fi->fib_clntref);
@@ -2938,7 +2948,6 @@ static int rt_fill_info(struct net *net,
29382948
struct rtmsg *r;
29392949
struct nlmsghdr *nlh;
29402950
unsigned long expires = 0;
2941-
const struct inet_peer *peer = rt->peer;
29422951
u32 id = 0, ts = 0, tsage = 0, error;
29432952

29442953
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
@@ -2994,8 +3003,9 @@ static int rt_fill_info(struct net *net,
29943003
goto nla_put_failure;
29953004

29963005
error = rt->dst.error;
2997-
if (peer) {
2998-
inet_peer_refcheck(rt->peer);
3006+
if (rt_has_peer(rt)) {
3007+
const struct inet_peer *peer = rt_peer_ptr(rt);
3008+
inet_peer_refcheck(peer);
29993009
id = atomic_read(&peer->ip_id_count) & 0xffff;
30003010
if (peer->tcp_ts_stamp) {
30013011
ts = peer->tcp_ts;

net/ipv4/xfrm4_policy.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
9090
xdst->u.dst.dev = dev;
9191
dev_hold(dev);
9292

93-
xdst->u.rt.peer = rt->peer;
94-
if (rt->peer)
95-
atomic_inc(&rt->peer->refcnt);
93+
rt_transfer_peer(&xdst->u.rt, rt);
9694

9795
/* Sheit... I remember I did this right. Apparently,
9896
* it was magically lost, so this code needs audit */
@@ -212,8 +210,10 @@ static void xfrm4_dst_destroy(struct dst_entry *dst)
212210

213211
dst_destroy_metrics_generic(dst);
214212

215-
if (likely(xdst->u.rt.peer))
216-
inet_putpeer(xdst->u.rt.peer);
213+
if (rt_has_peer(&xdst->u.rt)) {
214+
struct inet_peer *peer = rt_peer_ptr(&xdst->u.rt);
215+
inet_putpeer(peer);
216+
}
217217

218218
xfrm_dst_destroy(xdst);
219219
}

0 commit comments

Comments
 (0)