[INET]: Generalise tcp_v4_hash_connect

Renaming it to inet_hash_connect, making it possible to ditch
dccp_v4_hash_connect and share the same code with TCP instead.

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Arnaldo Carvalho de Melo
2005-12-13 23:25:31 -08:00
committed by David S. Miller
parent 6d6ee43e0b
commit a7f5e7f164
6 changed files with 186 additions and 336 deletions

View File

@ -54,164 +54,6 @@ void dccp_unhash(struct sock *sk)
EXPORT_SYMBOL_GPL(dccp_unhash);
/* called with local bh disabled */
static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
struct inet_timewait_sock **twp)
{
struct inet_sock *inet = inet_sk(sk);
const u32 daddr = inet->rcv_saddr;
const u32 saddr = inet->daddr;
const int dif = sk->sk_bound_dev_if;
INET_ADDR_COOKIE(acookie, saddr, daddr)
const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
struct inet_ehash_bucket *head = inet_ehash_bucket(&dccp_hashinfo, hash);
const struct sock *sk2;
const struct hlist_node *node;
struct inet_timewait_sock *tw;
prefetch(head->chain.first);
write_lock(&head->lock);
/* Check TIME-WAIT sockets first. */
sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) {
tw = inet_twsk(sk2);
if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
goto not_unique;
}
tw = NULL;
/* And established part... */
sk_for_each(sk2, node, &head->chain) {
if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
goto not_unique;
}
/* Must record num and sport now. Otherwise we will see
* in hash table socket with a funny identity. */
inet->num = lport;
inet->sport = htons(lport);
sk->sk_hash = hash;
BUG_TRAP(sk_unhashed(sk));
__sk_add_node(sk, &head->chain);
sock_prot_inc_use(sk->sk_prot);
write_unlock(&head->lock);
if (twp != NULL) {
*twp = tw;
NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
} else if (tw != NULL) {
/* Silly. Should hash-dance instead... */
inet_twsk_deschedule(tw, &dccp_death_row);
NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
inet_twsk_put(tw);
}
return 0;
not_unique:
write_unlock(&head->lock);
return -EADDRNOTAVAIL;
}
/*
* Bind a port for a connect operation and hash it.
*/
static int dccp_v4_hash_connect(struct sock *sk)
{
const unsigned short snum = inet_sk(sk)->num;
struct inet_bind_hashbucket *head;
struct inet_bind_bucket *tb;
int ret;
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;
struct hlist_node *node;
struct inet_timewait_sock *tw = NULL;
local_bh_disable();
do {
head = &dccp_hashinfo.bhash[inet_bhashfn(rover,
dccp_hashinfo.bhash_size)];
spin_lock(&head->lock);
/* Does not bother with rcv_saddr checks,
* because the established check is already
* unique enough.
*/
inet_bind_bucket_for_each(tb, node, &head->chain) {
if (tb->port == rover) {
BUG_TRAP(!hlist_empty(&tb->owners));
if (tb->fastreuse >= 0)
goto next_port;
if (!__dccp_v4_check_established(sk,
rover,
&tw))
goto ok;
goto next_port;
}
}
tb = inet_bind_bucket_create(dccp_hashinfo.bind_bucket_cachep,
head, rover);
if (tb == NULL) {
spin_unlock(&head->lock);
break;
}
tb->fastreuse = -1;
goto ok;
next_port:
spin_unlock(&head->lock);
if (++rover > high)
rover = low;
} while (--remaining > 0);
local_bh_enable();
return -EADDRNOTAVAIL;
ok:
/* All locks still held and bhs disabled */
inet_bind_hash(sk, tb, rover);
if (sk_unhashed(sk)) {
inet_sk(sk)->sport = htons(rover);
__inet_hash(&dccp_hashinfo, sk, 0);
}
spin_unlock(&head->lock);
if (tw != NULL) {
inet_twsk_deschedule(tw, &dccp_death_row);
inet_twsk_put(tw);
}
ret = 0;
goto out;
}
head = &dccp_hashinfo.bhash[inet_bhashfn(snum,
dccp_hashinfo.bhash_size)];
tb = inet_csk(sk)->icsk_bind_hash;
spin_lock_bh(&head->lock);
if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
__inet_hash(&dccp_hashinfo, sk, 0);
spin_unlock_bh(&head->lock);
return 0;
} else {
spin_unlock(&head->lock);
/* No definite answer... Walk to established hash table */
ret = __dccp_v4_check_established(sk, snum, NULL);
out:
local_bh_enable();
return ret;
}
}
int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
struct inet_sock *inet = inet_sk(sk);
@ -272,7 +114,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
* complete initialization after this.
*/
dccp_set_state(sk, DCCP_REQUESTING);
err = dccp_v4_hash_connect(sk);
err = inet_hash_connect(&dccp_death_row, sk);
if (err != 0)
goto failure;