[IPV6]: Reuse inet_csk_get_port in tcp_v6_get_port
authorArnaldo Carvalho de Melo <acme@mandriva.com>
Wed, 14 Dec 2005 07:14:47 +0000 (23:14 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Tue, 3 Jan 2006 21:10:33 +0000 (13:10 -0800)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/inet_connection_sock.h
net/dccp/ipv4.c
net/ipv4/inet_connection_sock.c
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c

index b0c9906..edc68e8 100644 (file)
@@ -192,8 +192,12 @@ extern struct request_sock *inet_csk_search_req(const struct sock *sk,
                                                const __u16 rport,
                                                const __u32 raddr,
                                                const __u32 laddr);
+extern int inet_csk_bind_conflict(const struct sock *sk,
+                                 const struct inet_bind_bucket *tb);
 extern int inet_csk_get_port(struct inet_hashinfo *hashinfo,
-                            struct sock *sk, unsigned short snum);
+                            struct sock *sk, unsigned short snum,
+                            int (*bind_conflict)(const struct sock *sk,
+                                                 const struct inet_bind_bucket *tb));
 
 extern struct dst_entry* inet_csk_route_req(struct sock *sk,
                                            const struct request_sock *req);
index 656e13e..1ac3e30 100644 (file)
@@ -37,7 +37,8 @@ EXPORT_SYMBOL_GPL(dccp_hashinfo);
 
 static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
 {
-       return inet_csk_get_port(&dccp_hashinfo, sk, snum);
+       return inet_csk_get_port(&dccp_hashinfo, sk, snum,
+                                inet_csk_bind_conflict);
 }
 
 static void dccp_v4_hash(struct sock *sk)
index 3fe021f..f05b6e7 100644 (file)
@@ -37,7 +37,8 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg);
  */
 int sysctl_local_port_range[2] = { 1024, 4999 };
 
-static inline int inet_csk_bind_conflict(struct sock *sk, struct inet_bind_bucket *tb)
+int inet_csk_bind_conflict(const struct sock *sk,
+                          const struct inet_bind_bucket *tb)
 {
        const u32 sk_rcv_saddr = inet_rcv_saddr(sk);
        struct sock *sk2;
@@ -62,11 +63,15 @@ static inline int inet_csk_bind_conflict(struct sock *sk, struct inet_bind_bucke
        return node != NULL;
 }
 
+EXPORT_SYMBOL_GPL(inet_csk_bind_conflict);
+
 /* Obtain a reference to a local port for the given sock,
  * if snum is zero it means select any available local port.
  */
 int inet_csk_get_port(struct inet_hashinfo *hashinfo,
-                     struct sock *sk, unsigned short snum)
+                     struct sock *sk, unsigned short snum,
+                     int (*bind_conflict)(const struct sock *sk,
+                                          const struct inet_bind_bucket *tb))
 {
        struct inet_bind_hashbucket *head;
        struct hlist_node *node;
@@ -125,7 +130,7 @@ tb_found:
                        goto success;
                } else {
                        ret = 1;
-                       if (inet_csk_bind_conflict(sk, tb))
+                       if (bind_conflict(sk, tb))
                                goto fail_unlock;
                }
        }
index 4d5021e..2aa19c8 100644 (file)
@@ -97,7 +97,8 @@ struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
 
 static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
 {
-       return inet_csk_get_port(&tcp_hashinfo, sk, snum);
+       return inet_csk_get_port(&tcp_hashinfo, sk, snum,
+                                inet_csk_bind_conflict);
 }
 
 static void tcp_v4_hash(struct sock *sk)
index 8827389..76c8f5a 100644 (file)
@@ -76,8 +76,8 @@ static int    tcp_v6_xmit(struct sk_buff *skb, int ipfragok);
 static struct tcp_func ipv6_mapped;
 static struct tcp_func ipv6_specific;
 
-static inline int tcp_v6_bind_conflict(const struct sock *sk,
-                                      const struct inet_bind_bucket *tb)
+int inet6_csk_bind_conflict(const struct sock *sk,
+                           const struct inet_bind_bucket *tb)
 {
        const struct sock *sk2;
        const struct hlist_node *node;
@@ -97,97 +97,10 @@ static inline int tcp_v6_bind_conflict(const struct sock *sk,
        return node != NULL;
 }
 
-/* Grrr, addr_type already calculated by caller, but I don't want
- * to add some silly "cookie" argument to this method just for that.
- * But it doesn't matter, the recalculation is in the rarest path
- * this function ever takes.
- */
 static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
 {
-       struct inet_bind_hashbucket *head;
-       struct inet_bind_bucket *tb;
-       struct hlist_node *node;
-       int ret;
-
-       local_bh_disable();
-       if (snum == 0) {
-               int low = sysctl_local_port_range[0];
-               int high = sysctl_local_port_range[1];
-               int remaining = (high - low) + 1;
-               int rover = net_random() % (high - low) + low;
-
-               do {
-                       head = &tcp_hashinfo.bhash[inet_bhashfn(rover, tcp_hashinfo.bhash_size)];
-                       spin_lock(&head->lock);
-                       inet_bind_bucket_for_each(tb, node, &head->chain)
-                               if (tb->port == rover)
-                                       goto next;
-                       break;
-               next:
-                       spin_unlock(&head->lock);
-                       if (++rover > high)
-                               rover = low;
-               } while (--remaining > 0);
-
-               /* Exhausted local port range during search?  It is not
-                * possible for us to be holding one of the bind hash
-                * locks if this test triggers, because if 'remaining'
-                * drops to zero, we broke out of the do/while loop at
-                * the top level, not from the 'break;' statement.
-                */
-               ret = 1;
-               if (unlikely(remaining <= 0))
-                       goto fail;
-
-               /* OK, here is the one we will use. */
-               snum = rover;
-       } else {
-               head = &tcp_hashinfo.bhash[inet_bhashfn(snum, tcp_hashinfo.bhash_size)];
-               spin_lock(&head->lock);
-               inet_bind_bucket_for_each(tb, node, &head->chain)
-                       if (tb->port == snum)
-                               goto tb_found;
-       }
-       tb = NULL;
-       goto tb_not_found;
-tb_found:
-       if (tb && !hlist_empty(&tb->owners)) {
-               if (tb->fastreuse > 0 && sk->sk_reuse &&
-                   sk->sk_state != TCP_LISTEN) {
-                       goto success;
-               } else {
-                       ret = 1;
-                       if (tcp_v6_bind_conflict(sk, tb))
-                               goto fail_unlock;
-               }
-       }
-tb_not_found:
-       ret = 1;
-       if (tb == NULL) {
-               tb = inet_bind_bucket_create(tcp_hashinfo.bind_bucket_cachep, head, snum);
-               if (tb == NULL)
-                       goto fail_unlock;
-       }
-       if (hlist_empty(&tb->owners)) {
-               if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
-                       tb->fastreuse = 1;
-               else
-                       tb->fastreuse = 0;
-       } else if (tb->fastreuse &&
-                  (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
-               tb->fastreuse = 0;
-
-success:
-       if (!inet_csk(sk)->icsk_bind_hash)
-               inet_bind_hash(sk, tb, snum);
-       BUG_TRAP(inet_csk(sk)->icsk_bind_hash == tb);
-       ret = 0;
-
-fail_unlock:
-       spin_unlock(&head->lock);
-fail:
-       local_bh_enable();
-       return ret;
+       return inet_csk_get_port(&tcp_hashinfo, sk, snum,
+                                inet6_csk_bind_conflict);
 }
 
 static __inline__ void __tcp_v6_hash(struct sock *sk)