浏览代码

[IPV6]: Reuse inet_csk_get_port in tcp_v6_get_port

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Arnaldo Carvalho de Melo 19 年之前
父节点
当前提交
971af18bbf
共有 5 个文件被更改,包括 21 次插入97 次删除
  1. 5 1
      include/net/inet_connection_sock.h
  2. 2 1
      net/dccp/ipv4.c
  3. 8 3
      net/ipv4/inet_connection_sock.c
  4. 2 1
      net/ipv4/tcp_ipv4.c
  5. 4 91
      net/ipv6/tcp_ipv6.c

+ 5 - 1
include/net/inet_connection_sock.h

@@ -192,8 +192,12 @@ extern struct request_sock *inet_csk_search_req(const struct sock *sk,
 						const __u16 rport,
 						const __u16 rport,
 						const __u32 raddr,
 						const __u32 raddr,
 						const __u32 laddr);
 						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,
 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,
 extern struct dst_entry* inet_csk_route_req(struct sock *sk,
 					    const struct request_sock *req);
 					    const struct request_sock *req);

+ 2 - 1
net/dccp/ipv4.c

@@ -37,7 +37,8 @@ EXPORT_SYMBOL_GPL(dccp_hashinfo);
 
 
 static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
 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)
 static void dccp_v4_hash(struct sock *sk)

+ 8 - 3
net/ipv4/inet_connection_sock.c

@@ -37,7 +37,8 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg);
  */
  */
 int sysctl_local_port_range[2] = { 1024, 4999 };
 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);
 	const u32 sk_rcv_saddr = inet_rcv_saddr(sk);
 	struct sock *sk2;
 	struct sock *sk2;
@@ -62,11 +63,15 @@ static inline int inet_csk_bind_conflict(struct sock *sk, struct inet_bind_bucke
 	return node != NULL;
 	return node != NULL;
 }
 }
 
 
+EXPORT_SYMBOL_GPL(inet_csk_bind_conflict);
+
 /* Obtain a reference to a local port for the given sock,
 /* Obtain a reference to a local port for the given sock,
  * if snum is zero it means select any available local port.
  * if snum is zero it means select any available local port.
  */
  */
 int inet_csk_get_port(struct inet_hashinfo *hashinfo,
 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 inet_bind_hashbucket *head;
 	struct hlist_node *node;
 	struct hlist_node *node;
@@ -125,7 +130,7 @@ tb_found:
 			goto success;
 			goto success;
 		} else {
 		} else {
 			ret = 1;
 			ret = 1;
-			if (inet_csk_bind_conflict(sk, tb))
+			if (bind_conflict(sk, tb))
 				goto fail_unlock;
 				goto fail_unlock;
 		}
 		}
 	}
 	}

+ 2 - 1
net/ipv4/tcp_ipv4.c

@@ -97,7 +97,8 @@ struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
 
 
 static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
 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)
 static void tcp_v4_hash(struct sock *sk)

+ 4 - 91
net/ipv6/tcp_ipv6.c

@@ -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_mapped;
 static struct tcp_func ipv6_specific;
 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 sock *sk2;
 	const struct hlist_node *node;
 	const struct hlist_node *node;
@@ -97,97 +97,10 @@ static inline int tcp_v6_bind_conflict(const struct sock *sk,
 	return node != NULL;
 	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)
 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)
 static __inline__ void __tcp_v6_hash(struct sock *sk)