[INET]: Generalise the TCP sock ID lookup routines
And also some TIME_WAIT functions. [acme@toy net-2.6.14]$ grep built-in /tmp/before.size /tmp/after.size /tmp/before.size: 282955 13122 9312 305389 4a8ed net/ipv4/built-in.o /tmp/after.size: 281566 13122 9312 304000 4a380 net/ipv4/built-in.o [acme@toy net-2.6.14]$ I kept them still inlined, will uninline at some point to see what would be the performance difference. Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
8feaf0c0a5
commit
e48c414ee6
|
@ -30,6 +30,7 @@
|
||||||
#include <net/tcp_states.h>
|
#include <net/tcp_states.h>
|
||||||
|
|
||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
|
#include <asm/byteorder.h>
|
||||||
|
|
||||||
/* This is for all connections with a full identity, no wildcards.
|
/* This is for all connections with a full identity, no wildcards.
|
||||||
* New scheme, half the table is for TIME_WAIT, the other half is
|
* New scheme, half the table is for TIME_WAIT, the other half is
|
||||||
|
@ -285,13 +286,13 @@ extern struct sock *__inet_lookup_listener(const struct hlist_head *head,
|
||||||
const int dif);
|
const int dif);
|
||||||
|
|
||||||
/* Optimize the common listener case. */
|
/* Optimize the common listener case. */
|
||||||
static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo,
|
static inline struct sock *
|
||||||
const u32 daddr,
|
inet_lookup_listener(struct inet_hashinfo *hashinfo,
|
||||||
const unsigned short hnum,
|
const u32 daddr,
|
||||||
const int dif)
|
const unsigned short hnum, const int dif)
|
||||||
{
|
{
|
||||||
struct sock *sk = NULL;
|
struct sock *sk = NULL;
|
||||||
struct hlist_head *head;
|
const struct hlist_head *head;
|
||||||
|
|
||||||
read_lock(&hashinfo->lhash_lock);
|
read_lock(&hashinfo->lhash_lock);
|
||||||
head = &hashinfo->listening_hash[inet_lhashfn(hnum)];
|
head = &hashinfo->listening_hash[inet_lhashfn(hnum)];
|
||||||
|
@ -351,4 +352,70 @@ sherry_cache:
|
||||||
((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
|
((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
|
||||||
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
|
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
|
||||||
#endif /* 64-bit arch */
|
#endif /* 64-bit arch */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so we need
|
||||||
|
* not check it for lookups anymore, thanks Alexey. -DaveM
|
||||||
|
*
|
||||||
|
* Local BH must be disabled here.
|
||||||
|
*/
|
||||||
|
static inline struct sock *
|
||||||
|
__inet_lookup_established(struct inet_hashinfo *hashinfo,
|
||||||
|
const u32 saddr, const u16 sport,
|
||||||
|
const u32 daddr, const u16 hnum,
|
||||||
|
const int dif)
|
||||||
|
{
|
||||||
|
INET_ADDR_COOKIE(acookie, saddr, daddr)
|
||||||
|
const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
|
||||||
|
struct sock *sk;
|
||||||
|
const struct hlist_node *node;
|
||||||
|
/* Optimize here for direct hit, only listening connections can
|
||||||
|
* have wildcards anyways.
|
||||||
|
*/
|
||||||
|
const int hash = inet_ehashfn(daddr, hnum, saddr, sport, hashinfo->ehash_size);
|
||||||
|
struct inet_ehash_bucket *head = &hashinfo->ehash[hash];
|
||||||
|
|
||||||
|
read_lock(&head->lock);
|
||||||
|
sk_for_each(sk, node, &head->chain) {
|
||||||
|
if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif))
|
||||||
|
goto hit; /* You sunk my battleship! */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must check for a TIME_WAIT'er before going to listener hash. */
|
||||||
|
sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
|
||||||
|
if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif))
|
||||||
|
goto hit;
|
||||||
|
}
|
||||||
|
sk = NULL;
|
||||||
|
out:
|
||||||
|
read_unlock(&head->lock);
|
||||||
|
return sk;
|
||||||
|
hit:
|
||||||
|
sock_hold(sk);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
|
||||||
|
const u32 saddr, const u16 sport,
|
||||||
|
const u32 daddr, const u16 hnum,
|
||||||
|
const int dif)
|
||||||
|
{
|
||||||
|
struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr,
|
||||||
|
hnum, dif);
|
||||||
|
return sk ? : inet_lookup_listener(hashinfo, daddr, hnum, dif);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
|
||||||
|
const u32 saddr, const u16 sport,
|
||||||
|
const u32 daddr, const u16 dport,
|
||||||
|
const int dif)
|
||||||
|
{
|
||||||
|
struct sock *sk;
|
||||||
|
|
||||||
|
local_bh_disable();
|
||||||
|
sk = __inet_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif);
|
||||||
|
local_bh_enable();
|
||||||
|
|
||||||
|
return sk;
|
||||||
|
}
|
||||||
#endif /* _INET_HASHTABLES_H */
|
#endif /* _INET_HASHTABLES_H */
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
|
|
||||||
|
#include <linux/ip.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct inet_bind_bucket;
|
struct inet_bind_bucket;
|
||||||
|
struct inet_hashinfo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a TIME_WAIT sock. It works around the memory consumption
|
* This is a TIME_WAIT sock. It works around the memory consumption
|
||||||
|
@ -139,4 +141,11 @@ static inline void inet_twsk_put(struct inet_timewait_sock *tw)
|
||||||
kmem_cache_free(tw->tw_prot->twsk_slab, tw);
|
kmem_cache_free(tw->tw_prot->twsk_slab, tw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void __inet_twsk_kill(struct inet_timewait_sock *tw,
|
||||||
|
struct inet_hashinfo *hashinfo);
|
||||||
|
|
||||||
|
extern void __inet_twsk_hashdance(struct inet_timewait_sock *tw,
|
||||||
|
struct sock *sk,
|
||||||
|
struct inet_hashinfo *hashinfo);
|
||||||
#endif /* _INET_TIMEWAIT_SOCK_ */
|
#endif /* _INET_TIMEWAIT_SOCK_ */
|
||||||
|
|
|
@ -255,28 +255,28 @@ struct sock {
|
||||||
/*
|
/*
|
||||||
* Hashed lists helper routines
|
* Hashed lists helper routines
|
||||||
*/
|
*/
|
||||||
static inline struct sock *__sk_head(struct hlist_head *head)
|
static inline struct sock *__sk_head(const struct hlist_head *head)
|
||||||
{
|
{
|
||||||
return hlist_entry(head->first, struct sock, sk_node);
|
return hlist_entry(head->first, struct sock, sk_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct sock *sk_head(struct hlist_head *head)
|
static inline struct sock *sk_head(const struct hlist_head *head)
|
||||||
{
|
{
|
||||||
return hlist_empty(head) ? NULL : __sk_head(head);
|
return hlist_empty(head) ? NULL : __sk_head(head);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct sock *sk_next(struct sock *sk)
|
static inline struct sock *sk_next(const struct sock *sk)
|
||||||
{
|
{
|
||||||
return sk->sk_node.next ?
|
return sk->sk_node.next ?
|
||||||
hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL;
|
hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int sk_unhashed(struct sock *sk)
|
static inline int sk_unhashed(const struct sock *sk)
|
||||||
{
|
{
|
||||||
return hlist_unhashed(&sk->sk_node);
|
return hlist_unhashed(&sk->sk_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int sk_hashed(struct sock *sk)
|
static inline int sk_hashed(const struct sock *sk)
|
||||||
{
|
{
|
||||||
return sk->sk_node.pprev != NULL;
|
return sk->sk_node.pprev != NULL;
|
||||||
}
|
}
|
||||||
|
@ -494,7 +494,7 @@ extern int sk_wait_data(struct sock *sk, long *timeo);
|
||||||
struct request_sock_ops;
|
struct request_sock_ops;
|
||||||
|
|
||||||
/* Here is the right place to enable sock refcounting debugging */
|
/* Here is the right place to enable sock refcounting debugging */
|
||||||
#define SOCK_REFCNT_DEBUG
|
//#define SOCK_REFCNT_DEBUG
|
||||||
|
|
||||||
/* Networking protocol blocks we attach to sockets.
|
/* Networking protocol blocks we attach to sockets.
|
||||||
* socket layer -> transport layer interface
|
* socket layer -> transport layer interface
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
obj-y := route.o inetpeer.o protocol.o \
|
obj-y := route.o inetpeer.o protocol.o \
|
||||||
ip_input.o ip_fragment.o ip_forward.o ip_options.o \
|
ip_input.o ip_fragment.o ip_forward.o ip_options.o \
|
||||||
ip_output.o ip_sockglue.o inet_hashtables.o \
|
ip_output.o ip_sockglue.o inet_hashtables.o \
|
||||||
|
inet_timewait_sock.o \
|
||||||
tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
|
tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
|
||||||
tcp_minisocks.o tcp_cong.o \
|
tcp_minisocks.o tcp_cong.o \
|
||||||
datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
|
datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
|
||||||
|
|
|
@ -162,3 +162,5 @@ struct sock *__inet_lookup_listener(const struct hlist_head *head, const u32 dad
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL_GPL(__inet_lookup_listener);
|
||||||
|
|
83
net/ipv4/inet_timewait_sock.c
Normal file
83
net/ipv4/inet_timewait_sock.c
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* INET An implementation of the TCP/IP protocol suite for the LINUX
|
||||||
|
* operating system. INET is implemented using the BSD Socket
|
||||||
|
* interface as the means of communication with the user level.
|
||||||
|
*
|
||||||
|
* Generic TIME_WAIT sockets functions
|
||||||
|
*
|
||||||
|
* From code orinally in TCP
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/config.h>
|
||||||
|
|
||||||
|
#include <net/inet_hashtables.h>
|
||||||
|
#include <net/inet_timewait_sock.h>
|
||||||
|
|
||||||
|
/* Must be called with locally disabled BHs. */
|
||||||
|
void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo)
|
||||||
|
{
|
||||||
|
struct inet_bind_hashbucket *bhead;
|
||||||
|
struct inet_bind_bucket *tb;
|
||||||
|
/* Unlink from established hashes. */
|
||||||
|
struct inet_ehash_bucket *ehead = &hashinfo->ehash[tw->tw_hashent];
|
||||||
|
|
||||||
|
write_lock(&ehead->lock);
|
||||||
|
if (hlist_unhashed(&tw->tw_node)) {
|
||||||
|
write_unlock(&ehead->lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
__hlist_del(&tw->tw_node);
|
||||||
|
sk_node_init(&tw->tw_node);
|
||||||
|
write_unlock(&ehead->lock);
|
||||||
|
|
||||||
|
/* Disassociate with bind bucket. */
|
||||||
|
bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, hashinfo->bhash_size)];
|
||||||
|
spin_lock(&bhead->lock);
|
||||||
|
tb = tw->tw_tb;
|
||||||
|
__hlist_del(&tw->tw_bind_node);
|
||||||
|
tw->tw_tb = NULL;
|
||||||
|
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
|
||||||
|
spin_unlock(&bhead->lock);
|
||||||
|
#ifdef SOCK_REFCNT_DEBUG
|
||||||
|
if (atomic_read(&tw->tw_refcnt) != 1) {
|
||||||
|
printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n",
|
||||||
|
tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
inet_twsk_put(tw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enter the time wait state. This is called with locally disabled BH.
|
||||||
|
* Essentially we whip up a timewait bucket, copy the relevant info into it
|
||||||
|
* from the SK, and mess with hash chains and list linkage.
|
||||||
|
*/
|
||||||
|
void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
|
||||||
|
struct inet_hashinfo *hashinfo)
|
||||||
|
{
|
||||||
|
const struct inet_sock *inet = inet_sk(sk);
|
||||||
|
struct inet_ehash_bucket *ehead = &hashinfo->ehash[sk->sk_hashent];
|
||||||
|
struct inet_bind_hashbucket *bhead;
|
||||||
|
/* Step 1: Put TW into bind hash. Original socket stays there too.
|
||||||
|
Note, that any socket with inet->num != 0 MUST be bound in
|
||||||
|
binding cache, even if it is closed.
|
||||||
|
*/
|
||||||
|
bhead = &hashinfo->bhash[inet_bhashfn(inet->num, hashinfo->bhash_size)];
|
||||||
|
spin_lock(&bhead->lock);
|
||||||
|
tw->tw_tb = inet->bind_hash;
|
||||||
|
BUG_TRAP(inet->bind_hash);
|
||||||
|
inet_twsk_add_bind_node(tw, &tw->tw_tb->owners);
|
||||||
|
spin_unlock(&bhead->lock);
|
||||||
|
|
||||||
|
write_lock(&ehead->lock);
|
||||||
|
|
||||||
|
/* Step 2: Remove SK from established hash. */
|
||||||
|
if (__sk_del_node_init(sk))
|
||||||
|
sock_prot_dec_use(sk->sk_prot);
|
||||||
|
|
||||||
|
/* Step 3: Hash TW into TIMEWAIT half of established hash table. */
|
||||||
|
inet_twsk_add_node(tw, &(ehead + hashinfo->ehash_size)->chain);
|
||||||
|
atomic_inc(&tw->tw_refcnt);
|
||||||
|
|
||||||
|
write_unlock(&ehead->lock);
|
||||||
|
}
|
|
@ -174,8 +174,6 @@ nlmsg_failure:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport,
|
|
||||||
int dif);
|
|
||||||
#ifdef CONFIG_IP_TCPDIAG_IPV6
|
#ifdef CONFIG_IP_TCPDIAG_IPV6
|
||||||
extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
|
extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
|
||||||
struct in6_addr *daddr, u16 dport,
|
struct in6_addr *daddr, u16 dport,
|
||||||
|
@ -197,9 +195,9 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
|
||||||
struct sk_buff *rep;
|
struct sk_buff *rep;
|
||||||
|
|
||||||
if (req->tcpdiag_family == AF_INET) {
|
if (req->tcpdiag_family == AF_INET) {
|
||||||
sk = tcp_v4_lookup(req->id.tcpdiag_dst[0], req->id.tcpdiag_dport,
|
sk = inet_lookup(&tcp_hashinfo, req->id.tcpdiag_dst[0],
|
||||||
req->id.tcpdiag_src[0], req->id.tcpdiag_sport,
|
req->id.tcpdiag_dport, req->id.tcpdiag_src[0],
|
||||||
req->id.tcpdiag_if);
|
req->id.tcpdiag_sport, req->id.tcpdiag_if);
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_IP_TCPDIAG_IPV6
|
#ifdef CONFIG_IP_TCPDIAG_IPV6
|
||||||
else if (req->tcpdiag_family == AF_INET6) {
|
else if (req->tcpdiag_family == AF_INET6) {
|
||||||
|
|
|
@ -238,71 +238,6 @@ void tcp_unhash(struct sock *sk)
|
||||||
inet_unhash(&tcp_hashinfo, sk);
|
inet_unhash(&tcp_hashinfo, sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
|
|
||||||
* we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
|
|
||||||
*
|
|
||||||
* Local BH must be disabled here.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline struct sock *__tcp_v4_lookup_established(const u32 saddr,
|
|
||||||
const u16 sport,
|
|
||||||
const u32 daddr,
|
|
||||||
const u16 hnum,
|
|
||||||
const int dif)
|
|
||||||
{
|
|
||||||
struct inet_ehash_bucket *head;
|
|
||||||
INET_ADDR_COOKIE(acookie, saddr, daddr)
|
|
||||||
const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
|
|
||||||
struct sock *sk;
|
|
||||||
const struct hlist_node *node;
|
|
||||||
/* Optimize here for direct hit, only listening connections can
|
|
||||||
* have wildcards anyways.
|
|
||||||
*/
|
|
||||||
const int hash = inet_ehashfn(daddr, hnum, saddr, sport, tcp_hashinfo.ehash_size);
|
|
||||||
head = &tcp_hashinfo.ehash[hash];
|
|
||||||
read_lock(&head->lock);
|
|
||||||
sk_for_each(sk, node, &head->chain) {
|
|
||||||
if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif))
|
|
||||||
goto hit; /* You sunk my battleship! */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Must check for a TIME_WAIT'er before going to listener hash. */
|
|
||||||
sk_for_each(sk, node, &(head + tcp_hashinfo.ehash_size)->chain) {
|
|
||||||
if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif))
|
|
||||||
goto hit;
|
|
||||||
}
|
|
||||||
sk = NULL;
|
|
||||||
out:
|
|
||||||
read_unlock(&head->lock);
|
|
||||||
return sk;
|
|
||||||
hit:
|
|
||||||
sock_hold(sk);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct sock *__tcp_v4_lookup(u32 saddr, u16 sport,
|
|
||||||
u32 daddr, u16 hnum, int dif)
|
|
||||||
{
|
|
||||||
struct sock *sk = __tcp_v4_lookup_established(saddr, sport,
|
|
||||||
daddr, hnum, dif);
|
|
||||||
|
|
||||||
return sk ? : inet_lookup_listener(&tcp_hashinfo, daddr, hnum, dif);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr,
|
|
||||||
u16 dport, int dif)
|
|
||||||
{
|
|
||||||
struct sock *sk;
|
|
||||||
|
|
||||||
local_bh_disable();
|
|
||||||
sk = __tcp_v4_lookup(saddr, sport, daddr, ntohs(dport), dif);
|
|
||||||
local_bh_enable();
|
|
||||||
|
|
||||||
return sk;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(tcp_v4_lookup);
|
|
||||||
|
|
||||||
static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
|
static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
return secure_tcp_sequence_number(skb->nh.iph->daddr,
|
return secure_tcp_sequence_number(skb->nh.iph->daddr,
|
||||||
|
@ -751,8 +686,8 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr,
|
sk = inet_lookup(&tcp_hashinfo, iph->daddr, th->dest, iph->saddr,
|
||||||
th->source, tcp_v4_iif(skb));
|
th->source, tcp_v4_iif(skb));
|
||||||
if (!sk) {
|
if (!sk) {
|
||||||
ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
|
ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
|
||||||
return;
|
return;
|
||||||
|
@ -1359,11 +1294,9 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
|
||||||
if (req)
|
if (req)
|
||||||
return tcp_check_req(sk, skb, req, prev);
|
return tcp_check_req(sk, skb, req, prev);
|
||||||
|
|
||||||
nsk = __tcp_v4_lookup_established(skb->nh.iph->saddr,
|
nsk = __inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr,
|
||||||
th->source,
|
th->source, skb->nh.iph->daddr,
|
||||||
skb->nh.iph->daddr,
|
ntohs(th->dest), tcp_v4_iif(skb));
|
||||||
ntohs(th->dest),
|
|
||||||
tcp_v4_iif(skb));
|
|
||||||
|
|
||||||
if (nsk) {
|
if (nsk) {
|
||||||
if (nsk->sk_state != TCP_TIME_WAIT) {
|
if (nsk->sk_state != TCP_TIME_WAIT) {
|
||||||
|
@ -1505,9 +1438,9 @@ int tcp_v4_rcv(struct sk_buff *skb)
|
||||||
TCP_SKB_CB(skb)->flags = skb->nh.iph->tos;
|
TCP_SKB_CB(skb)->flags = skb->nh.iph->tos;
|
||||||
TCP_SKB_CB(skb)->sacked = 0;
|
TCP_SKB_CB(skb)->sacked = 0;
|
||||||
|
|
||||||
sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source,
|
sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
|
||||||
skb->nh.iph->daddr, ntohs(th->dest),
|
skb->nh.iph->daddr, ntohs(th->dest),
|
||||||
tcp_v4_iif(skb));
|
tcp_v4_iif(skb));
|
||||||
|
|
||||||
if (!sk)
|
if (!sk)
|
||||||
goto no_tcp_socket;
|
goto no_tcp_socket;
|
||||||
|
|
|
@ -56,42 +56,6 @@ static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
|
||||||
|
|
||||||
int tcp_tw_count;
|
int tcp_tw_count;
|
||||||
|
|
||||||
|
|
||||||
/* Must be called with locally disabled BHs. */
|
|
||||||
static void tcp_timewait_kill(struct inet_timewait_sock *tw)
|
|
||||||
{
|
|
||||||
struct inet_bind_hashbucket *bhead;
|
|
||||||
struct inet_bind_bucket *tb;
|
|
||||||
/* Unlink from established hashes. */
|
|
||||||
struct inet_ehash_bucket *ehead = &tcp_hashinfo.ehash[tw->tw_hashent];
|
|
||||||
|
|
||||||
write_lock(&ehead->lock);
|
|
||||||
if (hlist_unhashed(&tw->tw_node)) {
|
|
||||||
write_unlock(&ehead->lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
__hlist_del(&tw->tw_node);
|
|
||||||
sk_node_init(&tw->tw_node);
|
|
||||||
write_unlock(&ehead->lock);
|
|
||||||
|
|
||||||
/* Disassociate with bind bucket. */
|
|
||||||
bhead = &tcp_hashinfo.bhash[inet_bhashfn(tw->tw_num, tcp_hashinfo.bhash_size)];
|
|
||||||
spin_lock(&bhead->lock);
|
|
||||||
tb = tw->tw_tb;
|
|
||||||
__hlist_del(&tw->tw_bind_node);
|
|
||||||
tw->tw_tb = NULL;
|
|
||||||
inet_bind_bucket_destroy(tcp_hashinfo.bind_bucket_cachep, tb);
|
|
||||||
spin_unlock(&bhead->lock);
|
|
||||||
|
|
||||||
#ifdef SOCK_REFCNT_DEBUG
|
|
||||||
if (atomic_read(&tw->tw_refcnt) != 1) {
|
|
||||||
printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n",
|
|
||||||
tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
inet_twsk_put(tw);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* * Main purpose of TIME-WAIT state is to close connection gracefully,
|
* * Main purpose of TIME-WAIT state is to close connection gracefully,
|
||||||
* when one of ends sits in LAST-ACK or CLOSING retransmitting FIN
|
* when one of ends sits in LAST-ACK or CLOSING retransmitting FIN
|
||||||
|
@ -290,40 +254,6 @@ kill:
|
||||||
return TCP_TW_SUCCESS;
|
return TCP_TW_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enter the time wait state. This is called with locally disabled BH.
|
|
||||||
* Essentially we whip up a timewait bucket, copy the
|
|
||||||
* relevant info into it from the SK, and mess with hash chains
|
|
||||||
* and list linkage.
|
|
||||||
*/
|
|
||||||
static void __tcp_tw_hashdance(struct sock *sk, struct inet_timewait_sock *tw)
|
|
||||||
{
|
|
||||||
const struct inet_sock *inet = inet_sk(sk);
|
|
||||||
struct inet_ehash_bucket *ehead = &tcp_hashinfo.ehash[sk->sk_hashent];
|
|
||||||
struct inet_bind_hashbucket *bhead;
|
|
||||||
/* Step 1: Put TW into bind hash. Original socket stays there too.
|
|
||||||
Note, that any socket with inet->num != 0 MUST be bound in
|
|
||||||
binding cache, even if it is closed.
|
|
||||||
*/
|
|
||||||
bhead = &tcp_hashinfo.bhash[inet_bhashfn(inet->num, tcp_hashinfo.bhash_size)];
|
|
||||||
spin_lock(&bhead->lock);
|
|
||||||
tw->tw_tb = inet->bind_hash;
|
|
||||||
BUG_TRAP(inet->bind_hash);
|
|
||||||
inet_twsk_add_bind_node(tw, &tw->tw_tb->owners);
|
|
||||||
spin_unlock(&bhead->lock);
|
|
||||||
|
|
||||||
write_lock(&ehead->lock);
|
|
||||||
|
|
||||||
/* Step 2: Remove SK from established hash. */
|
|
||||||
if (__sk_del_node_init(sk))
|
|
||||||
sock_prot_dec_use(sk->sk_prot);
|
|
||||||
|
|
||||||
/* Step 3: Hash TW into TIMEWAIT half of established hash table. */
|
|
||||||
inet_twsk_add_node(tw, &(ehead + tcp_hashinfo.ehash_size)->chain);
|
|
||||||
atomic_inc(&tw->tw_refcnt);
|
|
||||||
|
|
||||||
write_unlock(&ehead->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Move a socket to time-wait or dead fin-wait-2 state.
|
* Move a socket to time-wait or dead fin-wait-2 state.
|
||||||
*/
|
*/
|
||||||
|
@ -381,7 +311,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
|
||||||
tw->tw_ipv6only = 0;
|
tw->tw_ipv6only = 0;
|
||||||
#endif
|
#endif
|
||||||
/* Linkage updates. */
|
/* Linkage updates. */
|
||||||
__tcp_tw_hashdance(sk, tw);
|
__inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
|
||||||
|
|
||||||
/* Get the TIME_WAIT timeout firing. */
|
/* Get the TIME_WAIT timeout firing. */
|
||||||
if (timeo < rto)
|
if (timeo < rto)
|
||||||
|
@ -448,7 +378,7 @@ rescan:
|
||||||
inet_twsk_for_each_inmate(tw, node, &tcp_tw_death_row[slot]) {
|
inet_twsk_for_each_inmate(tw, node, &tcp_tw_death_row[slot]) {
|
||||||
__inet_twsk_del_dead_node(tw);
|
__inet_twsk_del_dead_node(tw);
|
||||||
spin_unlock(&tw_death_lock);
|
spin_unlock(&tw_death_lock);
|
||||||
tcp_timewait_kill(tw);
|
__inet_twsk_kill(tw, &tcp_hashinfo);
|
||||||
inet_twsk_put(tw);
|
inet_twsk_put(tw);
|
||||||
killed++;
|
killed++;
|
||||||
spin_lock(&tw_death_lock);
|
spin_lock(&tw_death_lock);
|
||||||
|
@ -544,7 +474,7 @@ void tcp_tw_deschedule(struct inet_timewait_sock *tw)
|
||||||
del_timer(&tcp_tw_timer);
|
del_timer(&tcp_tw_timer);
|
||||||
}
|
}
|
||||||
spin_unlock(&tw_death_lock);
|
spin_unlock(&tw_death_lock);
|
||||||
tcp_timewait_kill(tw);
|
__inet_twsk_kill(tw, &tcp_hashinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Short-time timewait calendar */
|
/* Short-time timewait calendar */
|
||||||
|
@ -653,7 +583,7 @@ void tcp_twcal_tick(unsigned long dummy)
|
||||||
inet_twsk_for_each_inmate_safe(tw, node, safe,
|
inet_twsk_for_each_inmate_safe(tw, node, safe,
|
||||||
&tcp_twcal_row[slot]) {
|
&tcp_twcal_row[slot]) {
|
||||||
__inet_twsk_del_dead_node(tw);
|
__inet_twsk_del_dead_node(tw);
|
||||||
tcp_timewait_kill(tw);
|
__inet_twsk_kill(tw, &tcp_hashinfo);
|
||||||
inet_twsk_put(tw);
|
inet_twsk_put(tw);
|
||||||
killed++;
|
killed++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue