sctp: apply rhashtable api to send/recv path
authorXin Long <lucien.xin@gmail.com>
Wed, 30 Dec 2015 15:50:47 +0000 (23:50 +0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 5 Jan 2016 17:24:01 +0000 (12:24 -0500)
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>
net/sctp/associola.c
net/sctp/endpointola.c
net/sctp/input.c
net/sctp/protocol.c

index 559afd0ee7de099ba013c8921045fedb4e7e5488..2bf8ec92dde482ed6ab59275aad492d5abc5385e 100644 (file)
@@ -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);
        }
 
@@ -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;
@@ -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) {
index 9da76ba4d10fe316884973448c19e5b9b8310a79..8838bf492a12c06621564b7a3f58f8e505990b66 100644 (file)
@@ -314,8 +314,8 @@ 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(
        const struct sctp_endpoint *ep,
@@ -323,12 +323,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
        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;
 
@@ -337,26 +332,12 @@ 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;
 }
index bac8278b176b765bd08798cc51533d602e47e893..6f075d83576416529da5d7788e55f457be11533e 100644 (file)
@@ -981,38 +981,19 @@ static struct sctp_association *__sctp_lookup_association(
                                        const union sctp_addr *peer,
                                        struct sctp_transport **pt)
 {
-       struct sctp_hashbucket *head;
-       struct sctp_ep_common *epb;
-       struct sctp_association *asoc;
-       struct sctp_transport *transport;
-       int hash;
+       struct sctp_transport *t;
 
-       /* 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;
-       }
+       t = sctp_addrs_lookup_transport(net, local, peer);
+       if (!t || t->dead || t->asoc->temp)
+               return NULL;
 
-       read_unlock(&head->lock);
+       sctp_association_hold(t->asoc);
+       *pt = t;
 
-       return NULL;
-
-hit:
-       *pt = transport;
-       sctp_association_hold(asoc);
-       read_unlock(&head->lock);
-       return asoc;
+       return t->asoc;
 }
 
-/* Look up an association. BH-safe. */
+/* Look up an association. protected by RCU read lock */
 static
 struct sctp_association *sctp_lookup_association(struct net *net,
                                                 const union sctp_addr *laddr,
@@ -1021,9 +1002,9 @@ struct sctp_association *sctp_lookup_association(struct net *net,
 {
        struct sctp_association *asoc;
 
-       local_bh_disable();
+       rcu_read_lock();
        asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
-       local_bh_enable();
+       rcu_read_unlock();
 
        return asoc;
 }
index 010aced44b6b23d0e57799674c6fbcc72af331e5..631cfb380535f398ba88cbe1b08cc53bfdd21cd6 100644 (file)
@@ -1467,6 +1467,9 @@ static __init int sctp_init(void)
                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",
                sctp_assoc_hashsize, sctp_port_hashsize);
 
@@ -1521,6 +1524,8 @@ err_register_defaults:
                   get_order(sctp_port_hashsize *
                             sizeof(struct sctp_bind_hashbucket)));
 err_bhash_alloc:
+       sctp_transport_hashtable_destroy();
+err_thash_alloc:
        kfree(sctp_ep_hashtable);
 err_ehash_alloc:
        free_pages((unsigned long)sctp_assoc_hashtable,
@@ -1567,6 +1572,7 @@ static __exit void sctp_exit(void)
        free_pages((unsigned long)sctp_port_hashtable,
                   get_order(sctp_port_hashsize *
                             sizeof(struct sctp_bind_hashbucket)));
+       sctp_transport_hashtable_destroy();
 
        percpu_counter_destroy(&sctp_sockets_allocated);