Недавно я изучал реализацию TCP / IP в ядре linux (версия 4.4), и был очень озадачен очередью принятия.Я знаю, что в struct inet_connection_sock
есть очередь, которая называется очередь приема :
struct inet_connection_sock {
...
/* @icsk_accept_queue: FIFO of established children */
struct request_sock_queue icsk_accept_queue;
...
}
, и в ней есть член qlen
, я думаю, она используется для указаниядлина очереди.
struct request_sock_queue {
...
/* length of the queue? */
atomic_t qlen;
...
};
Вот что, я думаю, я знаю: когда сокет LISTEN получает пакет SYN, в функции tcp_conn_request
, inet_csk_reqsk_queue_hash_add
вызываетсяпоместите вновь созданный носок NEW_SYN_RECV в таблицу ehash (не icsk_accept_queue
)
void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
unsigned long timeout)
{
reqsk_queue_hash_req(req, timeout); // add to ehash table
inet_csk_reqsk_queue_added(sk); // increment icsk_accept_queue.qlen
}
Но в этой функции inet_csk_reqsk_queue_added
вызывается с шагом icsk_accept_queue.qlen
.Мой вопрос, почему увеличение qlen
, так как ничего не вставлено в icsk_accept_queue
?Разве это не длина icsk_accept_queue?
Кроме того, tcp_conn_request
называется inet_csk_reqsk_queue_add
, чтобы добавить быстро открытый носок (если он включен) в icsk_accept_queue
:
struct sock *inet_csk_reqsk_queue_add(struct sock *sk,
struct request_sock *req,
struct sock *child)
{
struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
spin_lock(&queue->rskq_lock);
if (unlikely(sk->sk_state != TCP_LISTEN)) {
inet_child_forget(sk, req, child);
child = NULL;
} else {
req->sk = child;
req->dl_next = NULL;
if (queue->rskq_accept_head == NULL)
queue->rskq_accept_head = req;
else
queue->rskq_accept_tail->dl_next = req;
queue->rskq_accept_tail = req;
sk_acceptq_added(sk); // increment sk.sk_ack_backlog
}
spin_unlock(&queue->rskq_lock);
return child;
}
Но эта функция в итоге увеличила sk.sk_ack_backlog
(вызывая sk_acceptq_added
) вместо icsk_accept_queue.qlen
.Почему нет?