LinuxのTCP SYNの再送間隔の初期値が3秒から1秒に変更されていた

by felixtriller



ということに、(今更?)気付いたお話です。

HAを組んだ際のVIPの切り替えテストをやっているときに、高負荷時とかは切り替えに7秒ぴったりかかるケースとかがあって、7秒って何の数字だろうと疑問を持ちました。
OSは、CentOS 6.4(2.6.32-358.23.2.el6.x86_64)です。

TCP SYNの再送間隔が、1...2...4...秒になっている

で、tcpdumpを眺めていると以下のようなシーケンスです。

11:50:35.689301 IP client-host.8957 > server-host.http: Flags [S], seq 1616681830, win 14600, options [mss 1460,sackOK,TS val 889880946 ecr 0,nop,wscale 7], length 0
11:50:36.688503 IP client-host.8957 > server-host.http: Flags [S], seq 1616681830, win 14600, options [mss 1460,sackOK,TS val 889881946 ecr 0,nop,wscale 7], length 0
11:50:38.688540 IP client-host.8957 > server-host.http: Flags [S], seq 1616681830, win 14600, options [mss 1460,sackOK,TS val 889883946 ecr 0,nop,wscale 7], length 0
11:50:42.688557 IP client-host.8957 > server-host.http: Flags [S], seq 1616681830, win 14600, options [mss 1460,sackOK,TS val 889887946 ecr 0,nop,wscale 7], length 0
11:50:42.688993 IP server-host.http > client-host.8957: Flags [S.], seq 4112325498, ack 1616681831, win 14480, options [mss 1460,sackOK,TS val 346428911 ecr 889887946,nop,wscale 7], length 0

どうも、TCPのSYN再送が1, 2, 4秒の間隔で送られています
はて、Linux Kernelのデフォルトは3, 6, 12, 24・・・秒ではなかったかな、と。

TCP SYNの再送間隔は、どこで設定しているか

"/proc/sys/net/ipv4/tcp_syn_retries" この辺でSYNの再送回数をいじる話は良く聞くのですが、1発目の3秒とかは、どこで設定しているのかというところ。

色々調べていると、LinuxカーネルのコードのTCPまわり"include/net/tcp.h"に、RTO(Retransmission Time Out)の定義値があることに気付きました。

#define TCP_RTO_MAX     ((unsigned)(120*HZ))
#define TCP_RTO_MIN     ((unsigned)(HZ/5))
#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))     /* RFC2988bis initial RTO value */
#define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ)) /* RFC 1122 initial RTO value, now
                                                 * used as a fallback RTO for the
                                                 * initial data transmission if no
                                                 * valid RTT sample has been acquired,
                                                 * most likely due to retrans in 3WHS.
                                                 */

初期値だから「TCP_TIMEOUT_INIT」かと。"initial RTO value"と書いてあるし。

#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))     /* RFC2988bis initial RTO value */

確かに1秒になっていますね。


で、手元にちょっと古いCentOS 6.2(2.6.32-220.17.1.el6.x86_64)のサーバがあったので、こちらも "/usr/src/kernels/2.6.32-220.17.1.el6.x86_64/include/net/tcp.h" あたりを確認してみたところ、

#define TCP_TIMEOUT_INIT ((unsigned)(3*HZ))     /* RFC 1122 initial RTO value   */

おお、昔は3秒ですね。そうですよね。


つまりTCP再送の初期値を変更したかったら、この部分を変えてリビルドしなおしたらいいわけですね。ふむ。
("/proc/sys/net/ipv4/tcp_*"とかにそれっぽいのなかったんだよなぁ・・・。)

いつ変わったのか

Linux kernelのgitリポジトリを追っていると、

diff --git a/include/net/tcp.h b/include/net/tcp.h
index cda30ea..149a415 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -122,7 +122,13 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#endif
#define TCP_RTO_MAX ((unsigned)(120*HZ))
#define TCP_RTO_MIN ((unsigned)(HZ/5))
-#define TCP_TIMEOUT_INIT ((unsigned)(3*HZ)) /* RFC 1122 initial RTO value */
+#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ)) /* RFC2988bis initial RTO value */
+#define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ)) /* RFC 1122 initial RTO value, now
+ * used as a fallback RTO for the
+ * initial data transmission if no
+ * valid RTT sample has been acquired,
+ * most likely due to retrans in 3WHS.
+ */
#define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes
* for local resources.

・・・・・以下省略・・・・・

このコミットで変わっていることが確認できます。2011/6のコミットです。
Linux Kernelのバージョンでいうと、3.2のタイミングで取り込まれているようです。


CentOS的に、いつバックポートされたのかは、、、わかりませんw (雑ですみません。)
↑の通り、少なくともVer.6.2では3秒で、6.4では1秒でした。


と、今日はそんなところで。それでは!=͟͟͞͞(๑•̀=͟͟͞͞(๑•̀д•́=͟͟͞͞(๑•̀д•́๑)=͟͟͞͞(๑•̀д•́


詳解 Linuxカーネル 第3版

詳解 Linuxカーネル 第3版

  • 作者: Daniel P. Bovet,Marco Cesati,高橋浩和,杉田由美子,清水正明,高杉昌督,平松雅巳,安井隆宏
  • 出版社/メーカー: オライリー・ジャパン
  • 発売日: 2007/02/26
  • メディア: 大型本
  • 購入: 9人 クリック: 269回
  • この商品を含むブログ (73件) を見る
Linuxカーネル2.6解読室

Linuxカーネル2.6解読室