diff options
| author | Arnaldo Carvalho de Melo <acme@mandriva.com> | 2005-12-14 02:14:47 -0500 |
|---|---|---|
| committer | David S. Miller <davem@sunset.davemloft.net> | 2006-01-03 16:10:33 -0500 |
| commit | 971af18bbfabb7b7c9c548da34a51e30869c08fc (patch) | |
| tree | 02597aa6885b9937e1d6526f4789d6841953d551 | |
| parent | 89cee8b1cbb9dac40c92ef1968aea2b45f82fd18 (diff) | |
[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>
| -rw-r--r-- | include/net/inet_connection_sock.h | 6 | ||||
| -rw-r--r-- | net/dccp/ipv4.c | 3 | ||||
| -rw-r--r-- | net/ipv4/inet_connection_sock.c | 11 | ||||
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 3 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 95 |
5 files changed, 21 insertions, 97 deletions
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index b0c99060b78d..edc68e858d51 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h | |||
| @@ -192,8 +192,12 @@ extern struct request_sock *inet_csk_search_req(const struct sock *sk, | |||
| 192 | const __u16 rport, | 192 | const __u16 rport, |
| 193 | const __u32 raddr, | 193 | const __u32 raddr, |
| 194 | const __u32 laddr); | 194 | const __u32 laddr); |
| 195 | extern int inet_csk_bind_conflict(const struct sock *sk, | ||
| 196 | const struct inet_bind_bucket *tb); | ||
| 195 | extern int inet_csk_get_port(struct inet_hashinfo *hashinfo, | 197 | extern int inet_csk_get_port(struct inet_hashinfo *hashinfo, |
| 196 | struct sock *sk, unsigned short snum); | 198 | struct sock *sk, unsigned short snum, |
| 199 | int (*bind_conflict)(const struct sock *sk, | ||
| 200 | const struct inet_bind_bucket *tb)); | ||
| 197 | 201 | ||
| 198 | extern struct dst_entry* inet_csk_route_req(struct sock *sk, | 202 | extern struct dst_entry* inet_csk_route_req(struct sock *sk, |
| 199 | const struct request_sock *req); | 203 | const struct request_sock *req); |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 656e13e38cfb..1ac3e30ae791 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
| @@ -37,7 +37,8 @@ EXPORT_SYMBOL_GPL(dccp_hashinfo); | |||
| 37 | 37 | ||
| 38 | static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) | 38 | static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) |
| 39 | { | 39 | { |
| 40 | return inet_csk_get_port(&dccp_hashinfo, sk, snum); | 40 | return inet_csk_get_port(&dccp_hashinfo, sk, snum, |
| 41 | inet_csk_bind_conflict); | ||
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | static void dccp_v4_hash(struct sock *sk) | 44 | static void dccp_v4_hash(struct sock *sk) |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 3fe021f1a566..f05b6e761102 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
| @@ -37,7 +37,8 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg); | |||
| 37 | */ | 37 | */ |
| 38 | int sysctl_local_port_range[2] = { 1024, 4999 }; | 38 | int sysctl_local_port_range[2] = { 1024, 4999 }; |
| 39 | 39 | ||
| 40 | static inline int inet_csk_bind_conflict(struct sock *sk, struct inet_bind_bucket *tb) | 40 | int inet_csk_bind_conflict(const struct sock *sk, |
| 41 | const struct inet_bind_bucket *tb) | ||
| 41 | { | 42 | { |
| 42 | const u32 sk_rcv_saddr = inet_rcv_saddr(sk); | 43 | const u32 sk_rcv_saddr = inet_rcv_saddr(sk); |
| 43 | struct sock *sk2; | 44 | struct sock *sk2; |
| @@ -62,11 +63,15 @@ static inline int inet_csk_bind_conflict(struct sock *sk, struct inet_bind_bucke | |||
| 62 | return node != NULL; | 63 | return node != NULL; |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 66 | EXPORT_SYMBOL_GPL(inet_csk_bind_conflict); | ||
| 67 | |||
| 65 | /* Obtain a reference to a local port for the given sock, | 68 | /* Obtain a reference to a local port for the given sock, |
| 66 | * if snum is zero it means select any available local port. | 69 | * if snum is zero it means select any available local port. |
| 67 | */ | 70 | */ |
| 68 | int inet_csk_get_port(struct inet_hashinfo *hashinfo, | 71 | int inet_csk_get_port(struct inet_hashinfo *hashinfo, |
| 69 | struct sock *sk, unsigned short snum) | 72 | struct sock *sk, unsigned short snum, |
| 73 | int (*bind_conflict)(const struct sock *sk, | ||
| 74 | const struct inet_bind_bucket *tb)) | ||
| 70 | { | 75 | { |
| 71 | struct inet_bind_hashbucket *head; | 76 | struct inet_bind_hashbucket *head; |
| 72 | struct hlist_node *node; | 77 | struct hlist_node *node; |
| @@ -125,7 +130,7 @@ tb_found: | |||
| 125 | goto success; | 130 | goto success; |
| 126 | } else { | 131 | } else { |
| 127 | ret = 1; | 132 | ret = 1; |
| 128 | if (inet_csk_bind_conflict(sk, tb)) | 133 | if (bind_conflict(sk, tb)) |
| 129 | goto fail_unlock; | 134 | goto fail_unlock; |
| 130 | } | 135 | } |
| 131 | } | 136 | } |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 4d5021e1929b..2aa19c89a94a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -97,7 +97,8 @@ struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { | |||
| 97 | 97 | ||
| 98 | static int tcp_v4_get_port(struct sock *sk, unsigned short snum) | 98 | static int tcp_v4_get_port(struct sock *sk, unsigned short snum) |
| 99 | { | 99 | { |
| 100 | return inet_csk_get_port(&tcp_hashinfo, sk, snum); | 100 | return inet_csk_get_port(&tcp_hashinfo, sk, snum, |
| 101 | inet_csk_bind_conflict); | ||
| 101 | } | 102 | } |
| 102 | 103 | ||
| 103 | static void tcp_v4_hash(struct sock *sk) | 104 | static void tcp_v4_hash(struct sock *sk) |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8827389abaf7..76c8f5a2f7f3 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -76,8 +76,8 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok); | |||
| 76 | static struct tcp_func ipv6_mapped; | 76 | static struct tcp_func ipv6_mapped; |
| 77 | static struct tcp_func ipv6_specific; | 77 | static struct tcp_func ipv6_specific; |
| 78 | 78 | ||
| 79 | static inline int tcp_v6_bind_conflict(const struct sock *sk, | 79 | int inet6_csk_bind_conflict(const struct sock *sk, |
| 80 | const struct inet_bind_bucket *tb) | 80 | const struct inet_bind_bucket *tb) |
| 81 | { | 81 | { |
| 82 | const struct sock *sk2; | 82 | const struct sock *sk2; |
| 83 | const struct hlist_node *node; | 83 | const struct hlist_node *node; |
| @@ -97,97 +97,10 @@ static inline int tcp_v6_bind_conflict(const struct sock *sk, | |||
| 97 | return node != NULL; | 97 | return node != NULL; |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | /* Grrr, addr_type already calculated by caller, but I don't want | ||
| 101 | * to add some silly "cookie" argument to this method just for that. | ||
| 102 | * But it doesn't matter, the recalculation is in the rarest path | ||
| 103 | * this function ever takes. | ||
| 104 | */ | ||
| 105 | static int tcp_v6_get_port(struct sock *sk, unsigned short snum) | 100 | static int tcp_v6_get_port(struct sock *sk, unsigned short snum) |
| 106 | { | 101 | { |
| 107 | struct inet_bind_hashbucket *head; | 102 | return inet_csk_get_port(&tcp_hashinfo, sk, snum, |
| 108 | struct inet_bind_bucket *tb; | 103 | inet6_csk_bind_conflict); |
| 109 | struct hlist_node *node; | ||
| 110 | int ret; | ||
| 111 | |||
| 112 | local_bh_disable(); | ||
| 113 | if (snum == 0) { | ||
| 114 | int low = sysctl_local_port_range[0]; | ||
| 115 | int high = sysctl_local_port_range[1]; | ||
| 116 | int remaining = (high - low) + 1; | ||
| 117 | int rover = net_random() % (high - low) + low; | ||
| 118 | |||
| 119 | do { | ||
| 120 | head = &tcp_hashinfo.bhash[inet_bhashfn(rover, tcp_hashinfo.bhash_size)]; | ||
| 121 | spin_lock(&head->lock); | ||
| 122 | inet_bind_bucket_for_each(tb, node, &head->chain) | ||
| 123 | if (tb->port == rover) | ||
| 124 | goto next; | ||
| 125 | break; | ||
| 126 | next: | ||
| 127 | spin_unlock(&head->lock); | ||
| 128 | if (++rover > high) | ||
| 129 | rover = low; | ||
| 130 | } while (--remaining > 0); | ||
| 131 | |||
| 132 | /* Exhausted local port range during search? It is not | ||
| 133 | * possible for us to be holding one of the bind hash | ||
| 134 | * locks if this test triggers, because if 'remaining' | ||
| 135 | * drops to zero, we broke out of the do/while loop at | ||
| 136 | * the top level, not from the 'break;' statement. | ||
| 137 | */ | ||
| 138 | ret = 1; | ||
| 139 | if (unlikely(remaining <= 0)) | ||
| 140 | goto fail; | ||
| 141 | |||
| 142 | /* OK, here is the one we will use. */ | ||
| 143 | snum = rover; | ||
| 144 | } else { | ||
| 145 | head = &tcp_hashinfo.bhash[inet_bhashfn(snum, tcp_hashinfo.bhash_size)]; | ||
| 146 | spin_lock(&head->lock); | ||
| 147 | inet_bind_bucket_for_each(tb, node, &head->chain) | ||
| 148 | if (tb->port == snum) | ||
| 149 | goto tb_found; | ||
| 150 | } | ||
| 151 | tb = NULL; | ||
| 152 | goto tb_not_found; | ||
| 153 | tb_found: | ||
| 154 | if (tb && !hlist_empty(&tb->owners)) { | ||
| 155 | if (tb->fastreuse > 0 && sk->sk_reuse && | ||
| 156 | sk->sk_state != TCP_LISTEN) { | ||
| 157 | goto success; | ||
| 158 | } else { | ||
| 159 | ret = 1; | ||
| 160 | if (tcp_v6_bind_conflict(sk, tb)) | ||
| 161 | goto fail_unlock; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | tb_not_found: | ||
| 165 | ret = 1; | ||
| 166 | if (tb == NULL) { | ||
| 167 | tb = inet_bind_bucket_create(tcp_hashinfo.bind_bucket_cachep, head, snum); | ||
| 168 | if (tb == NULL) | ||
| 169 | goto fail_unlock; | ||
| 170 | } | ||
| 171 | if (hlist_empty(&tb->owners)) { | ||
| 172 | if (sk->sk_reuse && sk->sk_state != TCP_LISTEN) | ||
| 173 | tb->fastreuse = 1; | ||
| 174 | else | ||
| 175 | tb->fastreuse = 0; | ||
| 176 | } else if (tb->fastreuse && | ||
| 177 | (!sk->sk_reuse || sk->sk_state == TCP_LISTEN)) | ||
| 178 | tb->fastreuse = 0; | ||
| 179 | |||
| 180 | success: | ||
| 181 | if (!inet_csk(sk)->icsk_bind_hash) | ||
| 182 | inet_bind_hash(sk, tb, snum); | ||
| 183 | BUG_TRAP(inet_csk(sk)->icsk_bind_hash == tb); | ||
| 184 | ret = 0; | ||
| 185 | |||
| 186 | fail_unlock: | ||
| 187 | spin_unlock(&head->lock); | ||
| 188 | fail: | ||
| 189 | local_bh_enable(); | ||
| 190 | return ret; | ||
| 191 | } | 104 | } |
| 192 | 105 | ||
| 193 | static __inline__ void __tcp_v6_hash(struct sock *sk) | 106 | static __inline__ void __tcp_v6_hash(struct sock *sk) |
