TCP fastopen(TFO)を使うのに/proc/sys/net/ipv4/tcp_fastopenに整数値をセットするようだけど、その数値の意味は?というのがDocumentation/networking/ip-sysctl.txtにあったのでめも。ついでに一部実装も見てますが。
tcp_fastopenファイルに設定する値は整数値で設定できる数値は排他的では無くて(printkのログ出力レベルみたいな)、論理和をとって複数の項目を設定することができるんですね。
それで設定できる内容はドキュメントのtcp_fastopenの項目に。
476 The values (bitmap) are 477 1: Enables sending data in the opening SYN on the client. 478 2: Enables TCP Fast Open on the server side, i.e., allowing data in 479 a SYN packet to be accepted and passed to the application before 480 3-way hand shake finishes. 481 4: Send data in the opening SYN regardless of cookie availability and 482 without a cookie option. 483 0x100: Accept SYN data w/o validating the cookie. 484 0x200: Accept data-in-SYN w/o any cookie option present. 485 0x400/0x800: Enable Fast Open on all listeners regardless of the 486 TCP_FASTOPEN socket option. The two different flags designate two 487 different ways of setting max_qlen without the TCP_FASTOPEN socket 488 option. 489 490 Default: 0
デフォルト値は0だし、無効ってことですね。
そして1はクライアント側の項目ですね。
1: Enables sending data in the opening SYN on the client.
これでSYNパケット送信時にデータを送るのを有効に。
2はサーバ側ですね。
2: Enables TCP Fast Open on the server side, i.e., allowing data in a SYN packet to be accepted and passed to the application before 3-way hand shake finishes.
内容としては1と関係があって、クライアントがTCP FASTOPEN機能を使ったSYNパケットを送信して来たらそれを受け付けてデータをクライアントに返すようにする。これは3-way hand shake完了前に終わる。
tcp fastopenを試した人のブログだと/proc/sys/net/ipv4/tcp_fastopenを3に設定しているのはクライアント・サーバ共にtcp fastopenを有効にしている訳ですね。
次の4はクライアント側ですかね。
4: Send data in the opening SYN regardless of cookie availability and without a cookie option.
SYNパケットをクッキー無しで送る or クッキーオプション無しで送るのを許可する。このクッキーはlwn.netの記事のTFO cookieですな。
次は0x100でこれはサーバ側かな。
0x100: Accept SYN data w/o validating the cookie.
SYNパケットに有効なクッキーが無くてもOKにすると。
最後は、
0x400/0x800: Enable Fast Open on all listeners regardless of the TCP_FASTOPEN socket option. The two different flags designate two different ways of setting max_qlen without the TCP_FASTOPEN socket option.
すべてのリスナーをTFO有効にしてしまうというオプションですね。0x400と0x800の違いはmax_qlenが絡むのはわかるけど、何かと言うのはコードを見ないとだめですね。
TFOのリスナーはinclude/net/request_sock.hに構造体が定義されていて、このメンバ変数にmax_qlenがありますね。
112/* 113 * For a TCP Fast Open listener - 114 * lock - protects the access to all the reqsk, which is co-owned by 115 * the listener and the child socket. 116 * qlen - pending TFO requests (still in TCP_SYN_RECV). 117 * max_qlen - max TFO reqs allowed before TFO is disabled. 118 * 119 * XXX (TFO) - ideally these fields can be made as part of "listen_sock" 120 * structure above. But there is some implementation difficulty due to 121 * listen_sock being part of request_sock_queue hence will be freed when 122 * a listener is stopped. But TFO related fields may continue to be 123 * accessed even after a listener is closed, until its sk_refcnt drops 124 * to 0 implying no more outstanding TFO reqs. One solution is to keep 125 * listen_opt around until sk_refcnt drops to 0. But there is some other 126 * complexity that needs to be resolved. E.g., a listener can be disabled 127 * temporarily through shutdown()->tcp_disconnect(), and re-enabled later. 128 */ 129struct fastopen_queue { 130 struct request_sock *rskq_rst_head; /* Keep track of past TFO */ 131 struct request_sock *rskq_rst_tail; /* requests that caused RST. 132 * This is part of the defense 133 * against spoofing attack. 134 */ 135 spinlock_t lock; 136 int qlen; /* # of pending (TCP_SYN_RECV) reqs */ 137 int max_qlen; /* != 0 iff TFO is currently enabled */
コメントによるとmax_qlenはTFO有効化前にいくつリクエストを受け付けるかって設定ですね。
この辺の定数を探してみるとinclude/net/tcp.hでここまで見てきた数値が定義されてます。さらにTFO_SERVER_ALWAYSなんてのもあるけど。
225/* Bit Flags for sysctl_tcp_fastopen */ 226#define TFO_CLIENT_ENABLE 1 227#define TFO_SERVER_ENABLE 2 228#define TFO_CLIENT_NO_COOKIE 4 /* Data in SYN w/o cookie option */ 229 230/* Process SYN data but skip cookie validation */ 231#define TFO_SERVER_COOKIE_NOT_CHKED 0x100 232/* Accept SYN data w/o any cookie option */ 233#define TFO_SERVER_COOKIE_NOT_REQD 0x200 234 235/* Force enable TFO on all listeners, i.e., not requiring the 236 * TCP_FASTOPEN socket option. SOCKOPT1/2 determine how to set max_qlen. 237 */ 238#define TFO_SERVER_WO_SOCKOPT1 0x400 239#define TFO_SERVER_WO_SOCKOPT2 0x800 240/* Always create TFO child sockets on a TFO listener even when 241 * cookie/data not present. (For testing purpose!) 242 */ 243#define TFO_SERVER_ALWAYS 0x1000
では、この中でTFO_SERVER_WO_SOCKOPT1、TFO_SERVER_WO_SOCKOPT2がどこで使われるかというとnet/ipv4/af_inet.cのinet_listen()でした。まさしくな名前ですな。
このinet_listen()でどっちのフラグが立ってるかで処理が分かれます。といってもfastopen_init_queue()の2番目の引数(max_qlenの数)が変わるだけですが。
222 if ((sysctl_tcp_fastopen & TFO_SERVER_ENABLE) != 0 && 223 inet_csk(sk)->icsk_accept_queue.fastopenq == NULL) { 224 if ((sysctl_tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) != 0) 225 err = fastopen_init_queue(sk, backlog); 226 else if ((sysctl_tcp_fastopen & 227 TFO_SERVER_WO_SOCKOPT2) != 0) 228 err = fastopen_init_queue(sk, 229 ((uint)sysctl_tcp_fastopen) >> 16); 230 else 231 err = 0; 232 if (err) 233 goto out; 234 }
TFO_SERVER_WO_SOCKOPT1の時に渡すbacklogはinet_listen()の引数です。TFO_SERVER_WO_SOCKOPT2の場合はsysctl_tcp_fastopen(これは/proc/sys/net/ipv4/tcp_fastopenにセットした数値)を16bit右シフトしたものを使う。
ということで、これが0x400と0x800の違いですね。
ついでにfastopen_init_queue()を見てみます。これはinclude/linux/tcp.hにあります。
388static inline int fastopen_init_queue(struct sock *sk, int backlog) 389{ 390 struct request_sock_queue *queue = 391 &inet_csk(sk)->icsk_accept_queue; 392 393 if (queue->fastopenq == NULL) { 394 queue->fastopenq = kzalloc( 395 sizeof(struct fastopen_queue), 396 sk->sk_allocation); 397 if (queue->fastopenq == NULL) 398 return -ENOMEM; 399 400 sk->sk_destruct = tcp_sock_destruct; 401 spin_lock_init(&queue->fastopenq->lock); 402 } 403 queue->fastopenq->max_qlen = backlog; 404 return 0; 405}
やっていることはまあ普通な内容ですね。
さて、ここまでの内容をまとめると・・・
(´-`).。oO(特に理由が無ければ/proc/sys/net/ipv4/tcp_fastopenは3をセットしておけば良いんじゃないでしょうか
( ´Д`)ノ~