Blame view
net/rxrpc/peer_object.c
9.99 KB
be6e6707f rxrpc: Rework pee... |
1 |
/* RxRPC remote transport endpoint record management |
17926a793 [AF_RXRPC]: Provi... |
2 |
* |
be6e6707f rxrpc: Rework pee... |
3 |
* Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved. |
17926a793 [AF_RXRPC]: Provi... |
4 5 6 7 8 9 10 |
* Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ |
9b6d53985 rxrpc: Use pr_<le... |
11 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
17926a793 [AF_RXRPC]: Provi... |
12 13 14 15 16 |
#include <linux/module.h> #include <linux/net.h> #include <linux/skbuff.h> #include <linux/udp.h> #include <linux/in.h> |
75b54cb57 rxrpc: Add IPv6 s... |
17 |
#include <linux/in6.h> |
5a0e3ad6a include cleanup: ... |
18 |
#include <linux/slab.h> |
be6e6707f rxrpc: Rework pee... |
19 |
#include <linux/hashtable.h> |
17926a793 [AF_RXRPC]: Provi... |
20 21 22 |
#include <net/sock.h> #include <net/af_rxrpc.h> #include <net/ip.h> |
224711df5 [AF_RXRPC]: Sort ... |
23 |
#include <net/route.h> |
75b54cb57 rxrpc: Add IPv6 s... |
24 |
#include <net/ip6_route.h> |
17926a793 [AF_RXRPC]: Provi... |
25 |
#include "ar-internal.h" |
be6e6707f rxrpc: Rework pee... |
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/* * Hash a peer key. */ static unsigned long rxrpc_peer_hash_key(struct rxrpc_local *local, const struct sockaddr_rxrpc *srx) { const u16 *p; unsigned int i, size; unsigned long hash_key; _enter(""); hash_key = (unsigned long)local / __alignof__(*local); hash_key += srx->transport_type; hash_key += srx->transport_len; hash_key += srx->transport.family; switch (srx->transport.family) { case AF_INET: hash_key += (u16 __force)srx->transport.sin.sin_port; size = sizeof(srx->transport.sin.sin_addr); p = (u16 *)&srx->transport.sin.sin_addr; break; |
d19127473 rxrpc: Make IPv6 ... |
49 |
#ifdef CONFIG_AF_RXRPC_IPV6 |
75b54cb57 rxrpc: Add IPv6 s... |
50 51 52 53 54 |
case AF_INET6: hash_key += (u16 __force)srx->transport.sin.sin_port; size = sizeof(srx->transport.sin6.sin6_addr); p = (u16 *)&srx->transport.sin6.sin6_addr; break; |
d19127473 rxrpc: Make IPv6 ... |
55 |
#endif |
2f9f9f521 rxrpc: fix uninit... |
56 57 58 59 |
default: WARN(1, "AF_RXRPC: Unsupported transport address family "); return 0; |
be6e6707f rxrpc: Rework pee... |
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
} /* Step through the peer address in 16-bit portions for speed */ for (i = 0; i < size; i += sizeof(*p), p++) hash_key += *p; _leave(" 0x%lx", hash_key); return hash_key; } /* * Compare a peer to a key. Return -ve, 0 or +ve to indicate less than, same * or greater than. * * Unfortunately, the primitives in linux/hashtable.h don't allow for sorted * buckets and mid-bucket insertion, so we don't make full use of this * information at this point. */ static long rxrpc_peer_cmp_key(const struct rxrpc_peer *peer, struct rxrpc_local *local, const struct sockaddr_rxrpc *srx, unsigned long hash_key) { long diff; diff = ((peer->hash_key - hash_key) ?: ((unsigned long)peer->local - (unsigned long)local) ?: (peer->srx.transport_type - srx->transport_type) ?: (peer->srx.transport_len - srx->transport_len) ?: (peer->srx.transport.family - srx->transport.family)); if (diff != 0) return diff; switch (srx->transport.family) { case AF_INET: return ((u16 __force)peer->srx.transport.sin.sin_port - (u16 __force)srx->transport.sin.sin_port) ?: memcmp(&peer->srx.transport.sin.sin_addr, &srx->transport.sin.sin_addr, sizeof(struct in_addr)); |
d19127473 rxrpc: Make IPv6 ... |
100 |
#ifdef CONFIG_AF_RXRPC_IPV6 |
75b54cb57 rxrpc: Add IPv6 s... |
101 102 103 104 105 106 |
case AF_INET6: return ((u16 __force)peer->srx.transport.sin6.sin6_port - (u16 __force)srx->transport.sin6.sin6_port) ?: memcmp(&peer->srx.transport.sin6.sin6_addr, &srx->transport.sin6.sin6_addr, sizeof(struct in6_addr)); |
d19127473 rxrpc: Make IPv6 ... |
107 |
#endif |
be6e6707f rxrpc: Rework pee... |
108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
default: BUG(); } } /* * Look up a remote transport endpoint for the specified address using RCU. */ static struct rxrpc_peer *__rxrpc_lookup_peer_rcu( struct rxrpc_local *local, const struct sockaddr_rxrpc *srx, unsigned long hash_key) { struct rxrpc_peer *peer; |
2baec2c3f rxrpc: Support ne... |
122 |
struct rxrpc_net *rxnet = local->rxnet; |
be6e6707f rxrpc: Rework pee... |
123 |
|
2baec2c3f rxrpc: Support ne... |
124 |
hash_for_each_possible_rcu(rxnet->peer_hash, peer, hash_link, hash_key) { |
be6e6707f rxrpc: Rework pee... |
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
if (rxrpc_peer_cmp_key(peer, local, srx, hash_key) == 0) { if (atomic_read(&peer->usage) == 0) return NULL; return peer; } } return NULL; } /* * Look up a remote transport endpoint for the specified address using RCU. */ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local, const struct sockaddr_rxrpc *srx) { struct rxrpc_peer *peer; unsigned long hash_key = rxrpc_peer_hash_key(local, srx); peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); if (peer) { |
75b54cb57 rxrpc: Add IPv6 s... |
146 |
_net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport); |
be6e6707f rxrpc: Rework pee... |
147 148 149 150 |
_leave(" = %p {u=%d}", peer, atomic_read(&peer->usage)); } return peer; } |
17926a793 [AF_RXRPC]: Provi... |
151 152 |
/* |
224711df5 [AF_RXRPC]: Sort ... |
153 154 155 156 157 |
* assess the MTU size for the network interface through which this peer is * reached */ static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer) { |
75b54cb57 rxrpc: Add IPv6 s... |
158 |
struct dst_entry *dst; |
224711df5 [AF_RXRPC]: Sort ... |
159 |
struct rtable *rt; |
75b54cb57 rxrpc: Add IPv6 s... |
160 161 |
struct flowi fl; struct flowi4 *fl4 = &fl.u.ip4; |
d19127473 rxrpc: Make IPv6 ... |
162 |
#ifdef CONFIG_AF_RXRPC_IPV6 |
75b54cb57 rxrpc: Add IPv6 s... |
163 |
struct flowi6 *fl6 = &fl.u.ip6; |
d19127473 rxrpc: Make IPv6 ... |
164 |
#endif |
224711df5 [AF_RXRPC]: Sort ... |
165 166 |
peer->if_mtu = 1500; |
75b54cb57 rxrpc: Add IPv6 s... |
167 168 169 170 171 172 173 174 175 176 177 178 179 |
memset(&fl, 0, sizeof(fl)); switch (peer->srx.transport.family) { case AF_INET: rt = ip_route_output_ports( &init_net, fl4, NULL, peer->srx.transport.sin.sin_addr.s_addr, 0, htons(7000), htons(7001), IPPROTO_UDP, 0, 0); if (IS_ERR(rt)) { _leave(" [route err %ld]", PTR_ERR(rt)); return; } dst = &rt->dst; break; |
d19127473 rxrpc: Make IPv6 ... |
180 |
#ifdef CONFIG_AF_RXRPC_IPV6 |
75b54cb57 rxrpc: Add IPv6 s... |
181 182 183 184 185 186 187 188 189 |
case AF_INET6: fl6->flowi6_iif = LOOPBACK_IFINDEX; fl6->flowi6_scope = RT_SCOPE_UNIVERSE; fl6->flowi6_proto = IPPROTO_UDP; memcpy(&fl6->daddr, &peer->srx.transport.sin6.sin6_addr, sizeof(struct in6_addr)); fl6->fl6_dport = htons(7001); fl6->fl6_sport = htons(7000); dst = ip6_route_output(&init_net, NULL, fl6); |
07096f612 rxrpc: Fix checki... |
190 191 |
if (dst->error) { _leave(" [route err %d]", dst->error); |
75b54cb57 rxrpc: Add IPv6 s... |
192 193 194 |
return; } break; |
d19127473 rxrpc: Make IPv6 ... |
195 |
#endif |
75b54cb57 rxrpc: Add IPv6 s... |
196 197 198 |
default: BUG(); |
224711df5 [AF_RXRPC]: Sort ... |
199 |
} |
75b54cb57 rxrpc: Add IPv6 s... |
200 201 |
peer->if_mtu = dst_mtu(dst); dst_release(dst); |
224711df5 [AF_RXRPC]: Sort ... |
202 |
|
a6a62b69b AF_RXRPC: reduce ... |
203 |
_leave(" [if_mtu %u]", peer->if_mtu); |
224711df5 [AF_RXRPC]: Sort ... |
204 205 206 |
} /* |
be6e6707f rxrpc: Rework pee... |
207 |
* Allocate a peer. |
17926a793 [AF_RXRPC]: Provi... |
208 |
*/ |
be6e6707f rxrpc: Rework pee... |
209 |
struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp) |
17926a793 [AF_RXRPC]: Provi... |
210 211 212 213 214 215 216 |
{ struct rxrpc_peer *peer; _enter(""); peer = kzalloc(sizeof(struct rxrpc_peer), gfp); if (peer) { |
be6e6707f rxrpc: Rework pee... |
217 218 |
atomic_set(&peer->usage, 1); peer->local = local; |
f66d74901 rxrpc: Use the pe... |
219 220 221 |
INIT_HLIST_HEAD(&peer->error_targets); INIT_WORK(&peer->error_distributor, &rxrpc_peer_error_distributor); |
aa390bbe2 rxrpc: Kill off t... |
222 |
peer->service_conns = RB_ROOT; |
8496af50e rxrpc: Use RCU to... |
223 |
seqlock_init(&peer->service_conn_lock); |
17926a793 [AF_RXRPC]: Provi... |
224 |
spin_lock_init(&peer->lock); |
17926a793 [AF_RXRPC]: Provi... |
225 |
peer->debug_id = atomic_inc_return(&rxrpc_debug_id); |
f7aec129a rxrpc: Cache the ... |
226 227 228 229 230 231 232 |
if (RXRPC_TX_SMSS > 2190) peer->cong_cwnd = 2; else if (RXRPC_TX_SMSS > 1095) peer->cong_cwnd = 3; else peer->cong_cwnd = 4; |
be6e6707f rxrpc: Rework pee... |
233 234 235 236 237 238 239 |
} _leave(" = %p", peer); return peer; } /* |
248f219cb rxrpc: Rewrite th... |
240 241 242 243 |
* Initialise peer record. */ static void rxrpc_init_peer(struct rxrpc_peer *peer, unsigned long hash_key) { |
08a39685a rxrpc: Make sure ... |
244 |
peer->hash_key = hash_key; |
248f219cb rxrpc: Rewrite th... |
245 246 |
rxrpc_assess_MTU_size(peer); peer->mtu = peer->if_mtu; |
0d4b103c0 rxrpc: Reduce the... |
247 |
peer->rtt_last_req = ktime_get_real(); |
248f219cb rxrpc: Rewrite th... |
248 |
|
75b54cb57 rxrpc: Add IPv6 s... |
249 250 |
switch (peer->srx.transport.family) { case AF_INET: |
248f219cb rxrpc: Rewrite th... |
251 |
peer->hdrsize = sizeof(struct iphdr); |
75b54cb57 rxrpc: Add IPv6 s... |
252 |
break; |
d19127473 rxrpc: Make IPv6 ... |
253 |
#ifdef CONFIG_AF_RXRPC_IPV6 |
75b54cb57 rxrpc: Add IPv6 s... |
254 255 256 |
case AF_INET6: peer->hdrsize = sizeof(struct ipv6hdr); break; |
d19127473 rxrpc: Make IPv6 ... |
257 |
#endif |
75b54cb57 rxrpc: Add IPv6 s... |
258 259 260 261 262 263 264 265 266 |
default: BUG(); } switch (peer->srx.transport_type) { case SOCK_DGRAM: peer->hdrsize += sizeof(struct udphdr); break; default: |
248f219cb rxrpc: Rewrite th... |
267 268 269 270 271 272 273 274 |
BUG(); } peer->hdrsize += sizeof(struct rxrpc_wire_header); peer->maxdata = peer->mtu - peer->hdrsize; } /* |
be6e6707f rxrpc: Rework pee... |
275 276 277 278 279 280 281 282 283 284 285 286 287 |
* Set up a new peer. */ static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local, struct sockaddr_rxrpc *srx, unsigned long hash_key, gfp_t gfp) { struct rxrpc_peer *peer; _enter(""); peer = rxrpc_alloc_peer(local, gfp); if (peer) { |
17926a793 [AF_RXRPC]: Provi... |
288 |
memcpy(&peer->srx, srx, sizeof(*srx)); |
248f219cb rxrpc: Rewrite th... |
289 290 |
rxrpc_init_peer(peer, hash_key); } |
17926a793 [AF_RXRPC]: Provi... |
291 |
|
248f219cb rxrpc: Rewrite th... |
292 293 294 |
_leave(" = %p", peer); return peer; } |
17926a793 [AF_RXRPC]: Provi... |
295 |
|
248f219cb rxrpc: Rewrite th... |
296 297 298 299 300 301 302 303 |
/* * Set up a new incoming peer. The address is prestored in the preallocated * peer. */ struct rxrpc_peer *rxrpc_lookup_incoming_peer(struct rxrpc_local *local, struct rxrpc_peer *prealloc) { struct rxrpc_peer *peer; |
2baec2c3f rxrpc: Support ne... |
304 |
struct rxrpc_net *rxnet = local->rxnet; |
248f219cb rxrpc: Rewrite th... |
305 306 307 308 309 |
unsigned long hash_key; hash_key = rxrpc_peer_hash_key(local, &prealloc->srx); prealloc->local = local; rxrpc_init_peer(prealloc, hash_key); |
2baec2c3f rxrpc: Support ne... |
310 |
spin_lock(&rxnet->peer_hash_lock); |
248f219cb rxrpc: Rewrite th... |
311 312 313 314 315 316 317 |
/* Need to check that we aren't racing with someone else */ peer = __rxrpc_lookup_peer_rcu(local, &prealloc->srx, hash_key); if (peer && !rxrpc_get_peer_maybe(peer)) peer = NULL; if (!peer) { peer = prealloc; |
2baec2c3f rxrpc: Support ne... |
318 |
hash_add_rcu(rxnet->peer_hash, &peer->hash_link, hash_key); |
17926a793 [AF_RXRPC]: Provi... |
319 |
} |
2baec2c3f rxrpc: Support ne... |
320 |
spin_unlock(&rxnet->peer_hash_lock); |
17926a793 [AF_RXRPC]: Provi... |
321 322 323 324 325 326 |
return peer; } /* * obtain a remote transport endpoint for the specified address */ |
be6e6707f rxrpc: Rework pee... |
327 328 |
struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local, struct sockaddr_rxrpc *srx, gfp_t gfp) |
17926a793 [AF_RXRPC]: Provi... |
329 330 |
{ struct rxrpc_peer *peer, *candidate; |
2baec2c3f rxrpc: Support ne... |
331 |
struct rxrpc_net *rxnet = local->rxnet; |
be6e6707f rxrpc: Rework pee... |
332 |
unsigned long hash_key = rxrpc_peer_hash_key(local, srx); |
17926a793 [AF_RXRPC]: Provi... |
333 |
|
75b54cb57 rxrpc: Add IPv6 s... |
334 |
_enter("{%pISp}", &srx->transport); |
17926a793 [AF_RXRPC]: Provi... |
335 336 |
/* search the peer list first */ |
be6e6707f rxrpc: Rework pee... |
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
rcu_read_lock(); peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); if (peer && !rxrpc_get_peer_maybe(peer)) peer = NULL; rcu_read_unlock(); if (!peer) { /* The peer is not yet present in hash - create a candidate * for a new record and then redo the search. */ candidate = rxrpc_create_peer(local, srx, hash_key, gfp); if (!candidate) { _leave(" = NULL [nomem]"); return NULL; } |
17926a793 [AF_RXRPC]: Provi... |
352 |
|
2baec2c3f rxrpc: Support ne... |
353 |
spin_lock_bh(&rxnet->peer_hash_lock); |
17926a793 [AF_RXRPC]: Provi... |
354 |
|
be6e6707f rxrpc: Rework pee... |
355 356 357 358 359 |
/* Need to check that we aren't racing with someone else */ peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); if (peer && !rxrpc_get_peer_maybe(peer)) peer = NULL; if (!peer) |
2baec2c3f rxrpc: Support ne... |
360 |
hash_add_rcu(rxnet->peer_hash, |
be6e6707f rxrpc: Rework pee... |
361 |
&candidate->hash_link, hash_key); |
17926a793 [AF_RXRPC]: Provi... |
362 |
|
2baec2c3f rxrpc: Support ne... |
363 |
spin_unlock_bh(&rxnet->peer_hash_lock); |
17926a793 [AF_RXRPC]: Provi... |
364 |
|
be6e6707f rxrpc: Rework pee... |
365 366 367 368 369 |
if (peer) kfree(candidate); else peer = candidate; } |
17926a793 [AF_RXRPC]: Provi... |
370 |
|
75b54cb57 rxrpc: Add IPv6 s... |
371 |
_net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport); |
17926a793 [AF_RXRPC]: Provi... |
372 |
|
be6e6707f rxrpc: Rework pee... |
373 |
_leave(" = %p {u=%d}", peer, atomic_read(&peer->usage)); |
17926a793 [AF_RXRPC]: Provi... |
374 |
return peer; |
17926a793 [AF_RXRPC]: Provi... |
375 376 377 |
} /* |
be6e6707f rxrpc: Rework pee... |
378 |
* Discard a ref on a remote peer record. |
17926a793 [AF_RXRPC]: Provi... |
379 |
*/ |
be6e6707f rxrpc: Rework pee... |
380 |
void __rxrpc_put_peer(struct rxrpc_peer *peer) |
17926a793 [AF_RXRPC]: Provi... |
381 |
{ |
2baec2c3f rxrpc: Support ne... |
382 |
struct rxrpc_net *rxnet = peer->local->rxnet; |
f66d74901 rxrpc: Use the pe... |
383 |
ASSERT(hlist_empty(&peer->error_targets)); |
17926a793 [AF_RXRPC]: Provi... |
384 |
|
2baec2c3f rxrpc: Support ne... |
385 |
spin_lock_bh(&rxnet->peer_hash_lock); |
be6e6707f rxrpc: Rework pee... |
386 |
hash_del_rcu(&peer->hash_link); |
2baec2c3f rxrpc: Support ne... |
387 |
spin_unlock_bh(&rxnet->peer_hash_lock); |
17926a793 [AF_RXRPC]: Provi... |
388 |
|
be6e6707f rxrpc: Rework pee... |
389 |
kfree_rcu(peer, rcu); |
17926a793 [AF_RXRPC]: Provi... |
390 |
} |
8324f0bcf rxrpc: Provide a ... |
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
/** * rxrpc_kernel_get_peer - Get the peer address of a call * @sock: The socket on which the call is in progress. * @call: The call to query * @_srx: Where to place the result * * Get the address of the remote peer in a call. */ void rxrpc_kernel_get_peer(struct socket *sock, struct rxrpc_call *call, struct sockaddr_rxrpc *_srx) { *_srx = call->peer->srx; } EXPORT_SYMBOL(rxrpc_kernel_get_peer); |