连接请求块(request_sock)之于TCP三次握手,就如同网络数据包(sk_buff)之于网络协议栈,都是核心的数据结构。
内核版本:3.6
Author:zhangskd @ csdn blog
存储队列
连接请求块的存储队列:包括全连接队列、半连接队列。
-
-
-
-
struct inet_connection_sock {
-
...
-
-
struct request_sock_queue icsk_accept_queue;
-
...
-
};
-
-
-
-
-
-
-
-
struct request_sock_queue {
-
struct request_sock *rskq_accept_head;
-
struct request_sock *rskq_accept_tail;
-
-
rwlock_t syn_wait_lock;
-
u8 rskq_defer_accept;
-
-
-
struct listen_sock *listen_opt;
-
};
连接请求块(request_sock)保存在两个队列中:
(1) 处于SYN_RECV状态,即半连接队列
保存在icsk->icsk_accept_queue.listen_opt中,这个listen_sock实例在listen()后创建。
当客户端的ACK到达时,连接请求块会被移动到ESTABLISHED状态的连接请求块队列中。
注意,半连接队列是在listen()时创建的。
(2) 处于ESTABLISHED状态,即全连接队列
保存在icsk->icsk_accept_queue.rskq_accept_head和icsk->icsk_accept_queue.rskq_accept_tail
所指定的FIFO队列中。此队列的连接请求块等待accept()的获取。
listen_sock用于保存SYN_RECV状态的连接请求块,它的实例在listen()时创建。
-
-
-
-
-
-
struct listen_sock {
-
u8 max_qlen_log;
-
u8 synflood_warned;
-
-
int qlen;
-
int qlen_young;
-
int clock_hand;
-
u32 hash_rnd;
-
u32 nr_table_entries;
-
struct request_sock *syn_table[0];
-
};
连接请求块
最基本表示。
-
-
struct request_sock {
-
struct request_sock *dl_next;
-
-
u16 mss;
-
u8 retrans;
-
u8 cookie_ts;
-
u32 window_clamp;
-
u32 rcv_wnd;
-
u32 ts_recent;
-
unsigned long expires;
-
const struct request_sock_ops *rsk_ops;
-
struct sock *sk;
-
u32 secid;
-
u32 peer_secid;
-
};
inet层表示。
-
struct inet_request_sock {
-
struct request_sock req;
-
-
#if IS_ENABLED(CONFIG_IPV6)
-
u16 inet6_rsk_offset;
-
#endif
-
-
__be16 loc_port;
-
__be32 loc_addr;
-
__be32 rmt_addr;
-
__be16 rmt_port;
-
-
kmemcheck_bitfield_begin(flags);
-
u16 snd_wscale : 4,
-
rcv_wscale : 4,
-
tstamp_ok : 1,
-
sack_ok : 1,
-
wscale_ok : 1,
-
ecn_ok : 1,
-
acked : 1,
-
no_srccheck : 1;
-
kmemcheck_bitfield_end(flags);
-
-
struct ip_options_rcu *opt;
-
};
TCP层表示为tcp_request_sock。
-
struct tcp_request_sock {
-
struct inet_request_sock req;
-
-
#ifdef CONFIG_TCP_MD5SIG
-
-
const struct tcp_request_sock_ops *af_specific;
-
#endif
-
-
u32 rcv_isn;
-
u32 snt_isn;
-
u32 snt_synack;
-
};
操作函数
request_sock_ops为处理连接请求块的函数指针表,对于TCP,它的实例为tcp_request_sock_ops。
-
struct request_sock_ops {
-
int family;
-
int obj_size;
-
struct kmem_cache *slab;
-
char *slab_name;
-
-
-
int (*rtx_syn_ack) (struct sock *sk, struct request_sock *req, struct request_values *rvp);
-
-
-
void (*send_ack) (struct sock *sk, struct sk_buff *skb, struct request_sock *req);
-
-
-
void (*send_reset) (struct sock *sk, struct sk_buff *skb);
-
-
-
void (*destructor) (struct request_sock *req);
-
-
-
void (*syn_ack_timeout) (struct sock *sk, struct request_sock *req);
-
};
对于TCP,它的实例为tcp_request_sock_ops。
-
struct request_sock_ops tcp_request_sock_ops__read_mostly = {
-
.family = PF_INET,
-
.obj_size = sizeof(struct tcp_request_sock),
-
-
.rtx_syn_ack = tcp_v4_rtx_synack,
-
.send_ack = tcp_v4_reqsk_send_ack,
-
.destructor = tcp_v4_reqsk_destructor,
-
.send_reset = tcp_v4_send_reset,
-
.syn_ack_timeout = tcp_syn_ack_timeout,
-
};
建立连接时处理
(1)分配
从缓存块中分配一个request_sock实例,并指定此实例的操作函数集。
-
static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops)
-
{
-
struct request_sock *req = reqsk_alloc(ops);
-
struct inet_request_sock *ireq = inet_rsk(req);
-
-
if (req != NULL) {
-
kmemcheck_annotate_bitfield(ireq, flags);
-
ireq->opt = NULL;
-
}
-
-
return req;
-
}
-
-
static inline struct request_sock *reqsk_alloc(const struct request_sock_ops *ops)
-
{
-
struct request_sock *req = kmem_cache_alloc(ops->slab, GFP_ATOMIC);
-
if (req != NULL)
-
req->rsk_ops = ops;
-
return req;
-
}
(2)释放
释放一个request_sock实例。
-
static inline void reqsk_free(struct request_sock *req)
-
{
-
req->rsk_ops->destructor(req);
-
__reqsk_free(req);
-
}
-
-
-
static void tcp_v4_reqsk_destructor(struct request_sock *req)
-
{
-
kfree(inet_rsk(req)->opt);
-
}
-
-
static inline void __reqsk_free(struct request_sock *req)
-
{
-
kmem_cache_free(req->rsk_ops->slab, req);
-
}
(3)初始化
初始化连接请求块,包括request_sock、inet_request_sock、tcp_request_sock。
-
static inline void tcp_openreq_init(struct request_sock *req,
-
struct tcp_options_received *rx_opt, struct sk_buff *skb)
-
{
-
struct inet_request_sock *ireq = inet_rsk(req);
-
-
req->rcv_wnd = 0;
-
req->cookie_ts = 0;
-
tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
-
req->mss = rx_opt->mss_clamp;
-
req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0;
-
ireq->tstamp_ok = rx_opt->tstamp_ok;
-
ireq->sack_ok = rx_opt->sack_ok;
-
ireq->snd_wscale = rx_opt->snd_wscale;
-
ireq->wscale_ok = rx_opt->wscale_ok;
-
ireq->acked = 0;
-
ireq->ecn_ok = 0;
-
ireq->rmt_port = tcp_hdr(skb)->source;
-
ireq->loc_port = tcp_hdr(skb)->dest;
-
}
(4)入队列
把连接请求块链入半连接队列中。
-
void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, unsigned long timeout)
-
{
-
struct inet_connection_sock *icsk = inet_csk(sk);
-
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
-
-
-
const u32 h = inet_synq_hash(inet_rsk(req)->rmt_addr, inet_rsk(req)->rmt_port, lopt->hash_rnd,
-
lopt->nr_table_entries);
-
-
-
reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
-
-
-
inet_csk_reqsk_queue_added(sk, timeout);
-
}
设置连接请求块的超时时间、按照hash值把它链入半连接队列。
-
static inline void reqsk_queue_hash_req(struct request_sock_queue *queue, u32 hash,
-
struct request_sock *req, unsigned long timeout)
-
{
-
struct listen_sock *lopt = queue->listen_opt;
-
req->expires = jiffies + timeout;
-
req->retrans = 0;
-
req->sk = NULL;
-
req->dl_next = lopt->syn_table[hash];
-
-
write_lock(&queue->syn_wait_lock);
-
lopt->syn_table[hash] = req;
-
write_unlock(&queue->syn_wait_lock);
-
}
-
static inline void inet_csk_reqsk_queue_added(struct sock *sk, const unsigned long timeout)
-
{
-
-
if (reqsk_queue_added(&inet_csk(sk)->icsk_accept_queue) == 0)
-
inet_csk_reset_keepalive_timer(sk, timeout);
-
}
-
-
static inline int reqsk_queue_added(struct request_sock_queue *queue)
-
{
-
struct listen_opt *lopt = queue->listen_opt;
-
-
const int prev_qlen = lopt->qlen;
-
lopt->qlen_young++;
-
lopt->qlen++;
-
return prev_qlen;
-
}
-
-
void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len)
-
{
-
sk_reset_timer(sk, &sk->sk_timer, jiffies + len);
-
}
根据目的IP、目的端口和随机数,计算出该连接请求块的hash值。
-
static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport, const u32 rnd,
-
const u32 synq_hsize)
-
{
-
return jhash_2words((__force u32) raddr, (__force u32) rport, rnd) & (synq_hsize - 1);
-
}
-
-
static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
-
{
-
return jhash_3words(a, b, 0, initval);
-
}
-
-
static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
-
{
-
a += JHASH_INITVAL;
-
b += JHASH_INITVAL;
-
c += initval;
-
-
__jhash_final(a, b, c);
-
return c;
-
}
-
-
-
#define JHASH_INITVAL 0xdeadbeef
-
-
-
#define __jhash_final(a, b, c) \
-
{
-
c ^= b; c -= rol32(b, 14); \
-
a ^= c; a -= rol32(c, 11); \
-
b ^= a; b -= rol32(a, 25); \
-
c ^= b; c -= rol32(b, 16); \
-
a ^= c; a -= rol32(c, 4); \
-
b ^= a; b -= rol32(a, 14); \
-
c ^= b; c -= rol32(b, 24); \
-
}
-
-
-
-
-
-
-
static inline __u32 rol32(__u32 word, unsigned int shift)
-
{
-
return (word << shift) | (word >> (32 - shift));
-
}
(5) 出队列
把连接请求块从半连接队列中删除。
-
static inline void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req,
-
struct request_sock **prev)
-
{
-
inet_csk_reqsk_queue_unlink(sk, req, prev);
-
inet_csk_reqsk_queue_removed(sk, req);
-
reqsk_free(req);
-
}
-
-
static inline void inet_csk_reqsk_queue_unlink(struct sock *sk, struct request_sock *req,
-
struct request_sock **prev)
-
{
-
reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req, prev);
-
}
把连接请求块从半连接队列中删除。
-
static inline void reqsk_queue_unlink(struct request_sock_queue *queue, struct request_sock *req,
-
struct request_sock **prev_req)
-
{
-
write_lock(&queue->syn_wait_lock);
-
*prev_req = req->dl_next;
-
write_unlock(&queue->syn_wait_lock);
-
}
-
-
static inline void inet_csk_reqsk_queue_removed(struct sock *sk, struct request_sock *req)
-
{
-
-
if (reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req) == 0)
-
inet_csk_delete_keepalive_timer(sk);
-
}
更新未重传过的连接请求块数、更新半连接队列长度。
-
static inline int reqsk_queue_removed(struct request_sock_queue *queue, struct request_sock *req)
-
{
-
struct listen_sock *lopt = queue->listen_opt;
-
if (req->retrans == 0)
-
--lopt->qlen_yong;
-
return --lopt->qlen;
-
}
阅读(1672) | 评论(0) | 转发(1) |