I read some posts and checked Linux kernel code like inet_listen()
->inet_csk_listen_start()
and it seems that backlog
argument of listen()
syscall only affects on accepted queue, but not on SYN-received queue:
sk->sk_max_ack_backlog = backlog;
I.e. symbolically accept-queue + syn-received-queue != backlog
.
I can't figure out what is happening. This article states:
The maximum allowed length of both the Accept and SYN Queues is taken from the backlog parameter passed to the listen(2) syscall by the application.
But there is nothing similar in MAN page.
Also in case of Linux: Is backlog
a hint as mentioned here or it really limits queues?
TCP listen() BacklogThe backlog has an effect on the maximum rate at which a server can accept new TCP connections on a socket. The rate is a function of both the backlog value and the time that connections stay on the queue of partially open connections.
In simple words, the backlog parameter specifies the number of pending connections the queue will hold. When multiple clients connect to the server, the server then holds the incoming requests in a queue.
After the Client sends an SYN packet to the server, the server stores the socket connection to the SYN queue. If the Server determines that the queue is full, it will DROP the connection.
In case of 4.3 kernel you specified it's something like:
tcp_v4_do_rcv()
->tcp_rcv_state_process()
->tcp_v4_conn_request()
->tcp_conn_request()
->inet_csk_reqsk_queue_is_full()
Here we can see the most important details about queues:
/* TW buckets are converted to open requests without
* limitations, they conserve resources and peer is
* evidently real one.
*/
if ((sysctl_tcp_syncookies == 2 ||
inet_csk_reqsk_queue_is_full(sk)) && !isn) {
want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name);
if (!want_cookie)
goto drop;
}
/* Accept backlog is full. If we have already queued enough
* of warm entries in syn queue, drop request. It is better than
* clogging syn queue with openreqs with exponentially increasing
* timeout.
*/
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
goto drop;
}
Pay your attention to inet_csk_reqsk_queue_is_full()
:
static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk)
{
return inet_csk_reqsk_queue_len(sk) >= sk->sk_max_ack_backlog;
}
Finally it compares current queue icsk_accept_queue
with sk_max_ack_backlog
size which was previously set by inet_csk_listen_start()
. So yep, backlog
affects incoming queue in current case.
You can see that both sk_acceptq_is_full()
and inet_csk_reqsk_queue_is_full()
make comparison with the same socket's sk_max_ack_backlog
which is set through the listen()
:
static inline bool sk_acceptq_is_full(const struct sock *sk)
{
return sk->sk_ack_backlog > sk->sk_max_ack_backlog;
}
Useful links: 1, 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With