Skip to content

Commit

Permalink
Merge branch 'sctp-transport-rhashtable'
Browse files Browse the repository at this point in the history
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 <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jan 5, 2016
2 parents 6a5ef90 + c79c066 commit 33c1529
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 315 deletions.
32 changes: 11 additions & 21 deletions include/net/sctp/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,6 @@ int sctp_primitive_ASCONF(struct net *, struct sctp_association *, void *arg);
*/
int sctp_rcv(struct sk_buff *skb);
void sctp_v4_err(struct sk_buff *skb, u32 info);
void sctp_hash_established(struct sctp_association *);
void sctp_unhash_established(struct sctp_association *);
void sctp_hash_endpoint(struct sctp_endpoint *);
void sctp_unhash_endpoint(struct sctp_endpoint *);
struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
Expand All @@ -143,6 +141,17 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
struct sctp_transport *t);
void sctp_backlog_migrate(struct sctp_association *assoc,
struct sock *oldsk, struct sock *newsk);
int sctp_transport_hashtable_init(void);
void sctp_transport_hashtable_destroy(void);
void sctp_hash_transport(struct sctp_transport *t);
void sctp_unhash_transport(struct sctp_transport *t);
struct sctp_transport *sctp_addrs_lookup_transport(
struct net *net,
const union sctp_addr *laddr,
const union sctp_addr *paddr);
struct sctp_transport *sctp_epaddr_lookup_transport(
const struct sctp_endpoint *ep,
const union sctp_addr *paddr);

/*
* sctp/proc.c
Expand Down Expand Up @@ -519,25 +528,6 @@ static inline int sctp_ep_hashfn(struct net *net, __u16 lport)
return (net_hash_mix(net) + lport) & (sctp_ep_hashsize - 1);
}

/* This is the hash function for the association hash table. */
static inline int sctp_assoc_hashfn(struct net *net, __u16 lport, __u16 rport)
{
int h = (lport << 16) + rport + net_hash_mix(net);
h ^= h>>8;
return h & (sctp_assoc_hashsize - 1);
}

/* This is the hash function for the association hash table. This is
* not used yet, but could be used as a better hash function when
* we have a vtag.
*/
static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag)
{
int h = (lport << 16) + rport;
h ^= vtag;
return h & (sctp_assoc_hashsize - 1);
}

#define sctp_for_each_hentry(epb, head) \
hlist_for_each_entry(epb, head, node)

Expand Down
10 changes: 5 additions & 5 deletions include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#define __sctp_structs_h__

#include <linux/ktime.h>
#include <linux/rhashtable.h>
#include <linux/socket.h> /* linux/in.h needs this!! */
#include <linux/in.h> /* We get struct sockaddr_in. */
#include <linux/in6.h> /* We get struct in6_addr */
Expand Down Expand Up @@ -119,14 +120,13 @@ extern struct sctp_globals {

/* This is the hash of all endpoints. */
struct sctp_hashbucket *ep_hashtable;
/* This is the hash of all associations. */
struct sctp_hashbucket *assoc_hashtable;
/* This is the sctp port control hash. */
struct sctp_bind_hashbucket *port_hashtable;
/* This is the hash of all transports. */
struct rhashtable transport_hashtable;

/* Sizes of above hashtables. */
int ep_hashsize;
int assoc_hashsize;
int port_hashsize;

/* Default initialization values to be applied to new associations. */
Expand All @@ -143,10 +143,9 @@ extern struct sctp_globals {
#define sctp_address_families (sctp_globals.address_families)
#define sctp_ep_hashsize (sctp_globals.ep_hashsize)
#define sctp_ep_hashtable (sctp_globals.ep_hashtable)
#define sctp_assoc_hashsize (sctp_globals.assoc_hashsize)
#define sctp_assoc_hashtable (sctp_globals.assoc_hashtable)
#define sctp_port_hashsize (sctp_globals.port_hashsize)
#define sctp_port_hashtable (sctp_globals.port_hashtable)
#define sctp_transport_hashtable (sctp_globals.transport_hashtable)
#define sctp_checksum_disable (sctp_globals.checksum_disable)

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

/* Reference counting. */
atomic_t refcnt;
Expand Down
5 changes: 5 additions & 0 deletions net/sctp/associola.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ void sctp_association_free(struct sctp_association *asoc)
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport, transports);
list_del_rcu(pos);
sctp_unhash_transport(transport);
sctp_transport_free(transport);
}

Expand Down Expand Up @@ -500,6 +501,8 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,

/* Remove this peer from the list. */
list_del_rcu(&peer->transports);
/* Remove this peer from the transport hashtable */
sctp_unhash_transport(peer);

/* Get the first transport of asoc. */
pos = asoc->peer.transport_addr_list.next;
Expand Down Expand Up @@ -699,6 +702,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
/* Attach the remote transport to our asoc. */
list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list);
asoc->peer.transport_count++;
/* Add this peer into the transport hashtable */
sctp_hash_transport(peer);

/* If we do not yet have a primary path, set one. */
if (!asoc->peer.primary_path) {
Expand Down
52 changes: 9 additions & 43 deletions net/sctp/endpointola.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,21 +314,16 @@ struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
}

/* Find the association that goes with this chunk.
* We do a linear search of the associations for this endpoint.
* We return the matching transport address too.
* We lookup the transport from hashtable at first, then get association
* through t->assoc.
*/
static struct sctp_association *__sctp_endpoint_lookup_assoc(
struct sctp_association *sctp_endpoint_lookup_assoc(
const struct sctp_endpoint *ep,
const union sctp_addr *paddr,
struct sctp_transport **transport)
{
struct sctp_association *asoc = NULL;
struct sctp_association *tmp;
struct sctp_transport *t = NULL;
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
int hash;
int rport;
struct sctp_transport *t;

*transport = NULL;

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

rport = ntohs(paddr->v4.sin_port);

hash = sctp_assoc_hashfn(sock_net(ep->base.sk), ep->base.bind_addr.port,
rport);
head = &sctp_assoc_hashtable[hash];
read_lock(&head->lock);
sctp_for_each_hentry(epb, &head->chain) {
tmp = sctp_assoc(epb);
if (tmp->ep != ep || rport != tmp->peer.port)
continue;

t = sctp_assoc_lookup_paddr(tmp, paddr);
if (t) {
asoc = tmp;
*transport = t;
break;
}
}
read_unlock(&head->lock);
*transport = t;
asoc = t->asoc;
out:
return asoc;
}

/* Lookup association on an endpoint based on a peer address. BH-safe. */
struct sctp_association *sctp_endpoint_lookup_assoc(
const struct sctp_endpoint *ep,
const union sctp_addr *paddr,
struct sctp_transport **transport)
{
struct sctp_association *asoc;

local_bh_disable();
asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport);
local_bh_enable();

return asoc;
}

/* Look for any peeled off association from the endpoint that matches the
* given peer address.
*/
Expand Down
Loading

0 comments on commit 33c1529

Please sign in to comment.