sctp: apply rhashtable api to send/recv path

apply lookup apis to two functions, for __sctp_endpoint_lookup_assoc
and __sctp_lookup_association, it's invoked in the protection of sock
lock, it will be safe, but sctp_lookup_association need to call
rcu_read_lock() and to detect the t->dead to protect it.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Xin Long 2015-12-30 23:50:47 +08:00 committed by David S. Miller
parent d6c0256a60
commit 4f00878126
4 changed files with 29 additions and 56 deletions

View File

@ -383,6 +383,7 @@ void sctp_association_free(struct sctp_association *asoc)
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport, transports); transport = list_entry(pos, struct sctp_transport, transports);
list_del_rcu(pos); list_del_rcu(pos);
sctp_unhash_transport(transport);
sctp_transport_free(transport); sctp_transport_free(transport);
} }
@ -500,6 +501,8 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
/* Remove this peer from the list. */ /* Remove this peer from the list. */
list_del_rcu(&peer->transports); list_del_rcu(&peer->transports);
/* Remove this peer from the transport hashtable */
sctp_unhash_transport(peer);
/* Get the first transport of asoc. */ /* Get the first transport of asoc. */
pos = asoc->peer.transport_addr_list.next; pos = asoc->peer.transport_addr_list.next;
@ -699,6 +702,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
/* Attach the remote transport to our asoc. */ /* Attach the remote transport to our asoc. */
list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list); list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list);
asoc->peer.transport_count++; 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 we do not yet have a primary path, set one. */
if (!asoc->peer.primary_path) { if (!asoc->peer.primary_path) {

View File

@ -314,8 +314,8 @@ struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
} }
/* Find the association that goes with this chunk. /* Find the association that goes with this chunk.
* We do a linear search of the associations for this endpoint. * We lookup the transport from hashtable at first, then get association
* We return the matching transport address too. * through t->assoc.
*/ */
static struct sctp_association *__sctp_endpoint_lookup_assoc( static struct sctp_association *__sctp_endpoint_lookup_assoc(
const struct sctp_endpoint *ep, const struct sctp_endpoint *ep,
@ -323,12 +323,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
struct sctp_transport **transport) struct sctp_transport **transport)
{ {
struct sctp_association *asoc = NULL; struct sctp_association *asoc = NULL;
struct sctp_association *tmp; struct sctp_transport *t;
struct sctp_transport *t = NULL;
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
int hash;
int rport;
*transport = NULL; *transport = NULL;
@ -337,26 +332,12 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
*/ */
if (!ep->base.bind_addr.port) if (!ep->base.bind_addr.port)
goto out; 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; *transport = t;
break; asoc = t->asoc;
}
}
read_unlock(&head->lock);
out: out:
return asoc; return asoc;
} }

View File

@ -981,38 +981,19 @@ static struct sctp_association *__sctp_lookup_association(
const union sctp_addr *peer, const union sctp_addr *peer,
struct sctp_transport **pt) struct sctp_transport **pt)
{ {
struct sctp_hashbucket *head; struct sctp_transport *t;
struct sctp_ep_common *epb;
struct sctp_association *asoc;
struct sctp_transport *transport;
int hash;
/* Optimize here for direct hit, only listening connections can
* have wildcards anyways.
*/
hash = sctp_assoc_hashfn(net, ntohs(local->v4.sin_port),
ntohs(peer->v4.sin_port));
head = &sctp_assoc_hashtable[hash];
read_lock(&head->lock);
sctp_for_each_hentry(epb, &head->chain) {
asoc = sctp_assoc(epb);
transport = sctp_assoc_is_match(asoc, net, local, peer);
if (transport)
goto hit;
}
read_unlock(&head->lock);
t = sctp_addrs_lookup_transport(net, local, peer);
if (!t || t->dead || t->asoc->temp)
return NULL; return NULL;
hit: sctp_association_hold(t->asoc);
*pt = transport; *pt = t;
sctp_association_hold(asoc);
read_unlock(&head->lock); return t->asoc;
return asoc;
} }
/* Look up an association. BH-safe. */ /* Look up an association. protected by RCU read lock */
static static
struct sctp_association *sctp_lookup_association(struct net *net, struct sctp_association *sctp_lookup_association(struct net *net,
const union sctp_addr *laddr, const union sctp_addr *laddr,
@ -1021,9 +1002,9 @@ struct sctp_association *sctp_lookup_association(struct net *net,
{ {
struct sctp_association *asoc; struct sctp_association *asoc;
local_bh_disable(); rcu_read_lock();
asoc = __sctp_lookup_association(net, laddr, paddr, transportp); asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
local_bh_enable(); rcu_read_unlock();
return asoc; return asoc;
} }

View File

@ -1467,6 +1467,9 @@ static __init int sctp_init(void)
INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain); INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain);
} }
if (sctp_transport_hashtable_init())
goto err_thash_alloc;
pr_info("Hash tables configured (established %d bind %d)\n", pr_info("Hash tables configured (established %d bind %d)\n",
sctp_assoc_hashsize, sctp_port_hashsize); sctp_assoc_hashsize, sctp_port_hashsize);
@ -1521,6 +1524,8 @@ err_register_defaults:
get_order(sctp_port_hashsize * get_order(sctp_port_hashsize *
sizeof(struct sctp_bind_hashbucket))); sizeof(struct sctp_bind_hashbucket)));
err_bhash_alloc: err_bhash_alloc:
sctp_transport_hashtable_destroy();
err_thash_alloc:
kfree(sctp_ep_hashtable); kfree(sctp_ep_hashtable);
err_ehash_alloc: err_ehash_alloc:
free_pages((unsigned long)sctp_assoc_hashtable, free_pages((unsigned long)sctp_assoc_hashtable,
@ -1567,6 +1572,7 @@ static __exit void sctp_exit(void)
free_pages((unsigned long)sctp_port_hashtable, free_pages((unsigned long)sctp_port_hashtable,
get_order(sctp_port_hashsize * get_order(sctp_port_hashsize *
sizeof(struct sctp_bind_hashbucket))); sizeof(struct sctp_bind_hashbucket)));
sctp_transport_hashtable_destroy();
percpu_counter_destroy(&sctp_sockets_allocated); percpu_counter_destroy(&sctp_sockets_allocated);