Skip to content

Commit 33c1529

Browse files
committed
Merge branch 'sctp-transport-rhashtable'
Xin Long says: ==================== sctp: use transport hashtable to replace association's with rhashtable for telecom center, the usual case is that a server is connected by thousands of clients. but if the server with only one enpoint(udp style) use the same sport and dport to communicate with every clients, and every assoc in server will be hashed in the same chain of global assoc hashtable due to currently we choose dport and sport as the hash key. when a packet is received, sctp_rcv try to find the assoc with sport and dport, since that chain is too long to find it fast, it make the performance turn to very low, some test data is as follow: in server: $./ss [start a udp style server there] in client: $./cc [start 2500 sockets to connect server with same port and different ip, and use one of them to send data to server] ===== test on net-next -- perf top server: 55.73% [kernel] [k] sctp_assoc_is_match 6.80% [kernel] [k] sctp_assoc_lookup_paddr 4.81% [kernel] [k] sctp_v4_cmp_addr 3.12% [kernel] [k] _raw_spin_unlock_irqrestore 1.94% [kernel] [k] sctp_cmp_addr_exact client: 46.01% [kernel] [k] sctp_endpoint_lookup_assoc 5.55% libc-2.17.so [.] __libc_calloc 5.39% libc-2.17.so [.] _int_free 3.92% libc-2.17.so [.] _int_malloc 3.23% [kernel] [k] __memset -- spent time time is 487s, send pkt is 10000000 we need to change the way to calculate the hash key, to use lport + rport + paddr as the hash key can avoid this issue. besides, this patchset will use transport hashtable to replace association hashtable to lookup with rhashtable api. get transport first then get association by t->asoc. and also it will make tcp style work better. ===== test with this patchset: -- perf top server: 15.98% [kernel] [k] _raw_spin_unlock_irqrestore 9.92% [kernel] [k] __pv_queued_spin_lock_slowpath 7.22% [kernel] [k] copy_user_generic_string 2.38% libpthread-2.17.so [.] __recvmsg_nocancel 1.88% [kernel] [k] sctp_recvmsg client: 11.90% [kernel] [k] sctp_hash_cmp 8.52% [kernel] [k] rht_deferred_worker 4.94% [kernel] [k] __pv_queued_spin_lock_slowpath 3.95% [kernel] [k] sctp_bind_addr_match 2.49% [kernel] [k] __memset -- spent time time is 22s, send pkt is 10000000 ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 6a5ef90 + c79c066 commit 33c1529

File tree

9 files changed

+331
-315
lines changed

9 files changed

+331
-315
lines changed

include/net/sctp/sctp.h

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,6 @@ int sctp_primitive_ASCONF(struct net *, struct sctp_association *, void *arg);
126126
*/
127127
int sctp_rcv(struct sk_buff *skb);
128128
void sctp_v4_err(struct sk_buff *skb, u32 info);
129-
void sctp_hash_established(struct sctp_association *);
130-
void sctp_unhash_established(struct sctp_association *);
131129
void sctp_hash_endpoint(struct sctp_endpoint *);
132130
void sctp_unhash_endpoint(struct sctp_endpoint *);
133131
struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
@@ -143,6 +141,17 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
143141
struct sctp_transport *t);
144142
void sctp_backlog_migrate(struct sctp_association *assoc,
145143
struct sock *oldsk, struct sock *newsk);
144+
int sctp_transport_hashtable_init(void);
145+
void sctp_transport_hashtable_destroy(void);
146+
void sctp_hash_transport(struct sctp_transport *t);
147+
void sctp_unhash_transport(struct sctp_transport *t);
148+
struct sctp_transport *sctp_addrs_lookup_transport(
149+
struct net *net,
150+
const union sctp_addr *laddr,
151+
const union sctp_addr *paddr);
152+
struct sctp_transport *sctp_epaddr_lookup_transport(
153+
const struct sctp_endpoint *ep,
154+
const union sctp_addr *paddr);
146155

147156
/*
148157
* sctp/proc.c
@@ -519,25 +528,6 @@ static inline int sctp_ep_hashfn(struct net *net, __u16 lport)
519528
return (net_hash_mix(net) + lport) & (sctp_ep_hashsize - 1);
520529
}
521530

522-
/* This is the hash function for the association hash table. */
523-
static inline int sctp_assoc_hashfn(struct net *net, __u16 lport, __u16 rport)
524-
{
525-
int h = (lport << 16) + rport + net_hash_mix(net);
526-
h ^= h>>8;
527-
return h & (sctp_assoc_hashsize - 1);
528-
}
529-
530-
/* This is the hash function for the association hash table. This is
531-
* not used yet, but could be used as a better hash function when
532-
* we have a vtag.
533-
*/
534-
static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag)
535-
{
536-
int h = (lport << 16) + rport;
537-
h ^= vtag;
538-
return h & (sctp_assoc_hashsize - 1);
539-
}
540-
541531
#define sctp_for_each_hentry(epb, head) \
542532
hlist_for_each_entry(epb, head, node)
543533

include/net/sctp/structs.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#define __sctp_structs_h__
4949

5050
#include <linux/ktime.h>
51+
#include <linux/rhashtable.h>
5152
#include <linux/socket.h> /* linux/in.h needs this!! */
5253
#include <linux/in.h> /* We get struct sockaddr_in. */
5354
#include <linux/in6.h> /* We get struct in6_addr */
@@ -119,14 +120,13 @@ extern struct sctp_globals {
119120

120121
/* This is the hash of all endpoints. */
121122
struct sctp_hashbucket *ep_hashtable;
122-
/* This is the hash of all associations. */
123-
struct sctp_hashbucket *assoc_hashtable;
124123
/* This is the sctp port control hash. */
125124
struct sctp_bind_hashbucket *port_hashtable;
125+
/* This is the hash of all transports. */
126+
struct rhashtable transport_hashtable;
126127

127128
/* Sizes of above hashtables. */
128129
int ep_hashsize;
129-
int assoc_hashsize;
130130
int port_hashsize;
131131

132132
/* Default initialization values to be applied to new associations. */
@@ -143,10 +143,9 @@ extern struct sctp_globals {
143143
#define sctp_address_families (sctp_globals.address_families)
144144
#define sctp_ep_hashsize (sctp_globals.ep_hashsize)
145145
#define sctp_ep_hashtable (sctp_globals.ep_hashtable)
146-
#define sctp_assoc_hashsize (sctp_globals.assoc_hashsize)
147-
#define sctp_assoc_hashtable (sctp_globals.assoc_hashtable)
148146
#define sctp_port_hashsize (sctp_globals.port_hashsize)
149147
#define sctp_port_hashtable (sctp_globals.port_hashtable)
148+
#define sctp_transport_hashtable (sctp_globals.transport_hashtable)
150149
#define sctp_checksum_disable (sctp_globals.checksum_disable)
151150

152151
/* SCTP Socket type: UDP or TCP style. */
@@ -753,6 +752,7 @@ static inline int sctp_packet_empty(struct sctp_packet *packet)
753752
struct sctp_transport {
754753
/* A list of transports. */
755754
struct list_head transports;
755+
struct rhash_head node;
756756

757757
/* Reference counting. */
758758
atomic_t refcnt;

net/sctp/associola.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ void sctp_association_free(struct sctp_association *asoc)
383383
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
384384
transport = list_entry(pos, struct sctp_transport, transports);
385385
list_del_rcu(pos);
386+
sctp_unhash_transport(transport);
386387
sctp_transport_free(transport);
387388
}
388389

@@ -500,6 +501,8 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
500501

501502
/* Remove this peer from the list. */
502503
list_del_rcu(&peer->transports);
504+
/* Remove this peer from the transport hashtable */
505+
sctp_unhash_transport(peer);
503506

504507
/* Get the first transport of asoc. */
505508
pos = asoc->peer.transport_addr_list.next;
@@ -699,6 +702,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
699702
/* Attach the remote transport to our asoc. */
700703
list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list);
701704
asoc->peer.transport_count++;
705+
/* Add this peer into the transport hashtable */
706+
sctp_hash_transport(peer);
702707

703708
/* If we do not yet have a primary path, set one. */
704709
if (!asoc->peer.primary_path) {

net/sctp/endpointola.c

Lines changed: 9 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -314,21 +314,16 @@ struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
314314
}
315315

316316
/* Find the association that goes with this chunk.
317-
* We do a linear search of the associations for this endpoint.
318-
* We return the matching transport address too.
317+
* We lookup the transport from hashtable at first, then get association
318+
* through t->assoc.
319319
*/
320-
static struct sctp_association *__sctp_endpoint_lookup_assoc(
320+
struct sctp_association *sctp_endpoint_lookup_assoc(
321321
const struct sctp_endpoint *ep,
322322
const union sctp_addr *paddr,
323323
struct sctp_transport **transport)
324324
{
325325
struct sctp_association *asoc = NULL;
326-
struct sctp_association *tmp;
327-
struct sctp_transport *t = NULL;
328-
struct sctp_hashbucket *head;
329-
struct sctp_ep_common *epb;
330-
int hash;
331-
int rport;
326+
struct sctp_transport *t;
332327

333328
*transport = NULL;
334329

@@ -337,45 +332,16 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
337332
*/
338333
if (!ep->base.bind_addr.port)
339334
goto out;
335+
t = sctp_epaddr_lookup_transport(ep, paddr);
336+
if (!t || t->asoc->temp)
337+
goto out;
340338

341-
rport = ntohs(paddr->v4.sin_port);
342-
343-
hash = sctp_assoc_hashfn(sock_net(ep->base.sk), ep->base.bind_addr.port,
344-
rport);
345-
head = &sctp_assoc_hashtable[hash];
346-
read_lock(&head->lock);
347-
sctp_for_each_hentry(epb, &head->chain) {
348-
tmp = sctp_assoc(epb);
349-
if (tmp->ep != ep || rport != tmp->peer.port)
350-
continue;
351-
352-
t = sctp_assoc_lookup_paddr(tmp, paddr);
353-
if (t) {
354-
asoc = tmp;
355-
*transport = t;
356-
break;
357-
}
358-
}
359-
read_unlock(&head->lock);
339+
*transport = t;
340+
asoc = t->asoc;
360341
out:
361342
return asoc;
362343
}
363344

364-
/* Lookup association on an endpoint based on a peer address. BH-safe. */
365-
struct sctp_association *sctp_endpoint_lookup_assoc(
366-
const struct sctp_endpoint *ep,
367-
const union sctp_addr *paddr,
368-
struct sctp_transport **transport)
369-
{
370-
struct sctp_association *asoc;
371-
372-
local_bh_disable();
373-
asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport);
374-
local_bh_enable();
375-
376-
return asoc;
377-
}
378-
379345
/* Look for any peeled off association from the endpoint that matches the
380346
* given peer address.
381347
*/

0 commit comments

Comments
 (0)