hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

カーネルパラメータの使い方(tcp_tw_reuse編)



1 tcp_tw_reuseとは?

tcp_tw_reuseは、TCPコネクション確立時に使用していたローカルポートをTIME-WAIT状態のソケットで使用できるかどうかを指定するカーネルパラメータです。

tcp_tw_reuseが1の場合、クライアントが時刻T1のときに使用していたローカルポート(P1)を使って、時刻T2でサーバとTCPコネクションを確立することができます。一方、tcp_tw_reuseが2(デフォルト値)の場合、このようなことはできません。クライアントがP1を使ってサーバとTCPコネクションを確立するには、時刻T3でソケットの状態がTIME-WAITからCLOSEDになってからです。なお、TCPの状態については、TCPの各種状態の作り方 - hana_shinのLinux技術ブログを参照してください。

  TIME       client                              server
   |           |                                   |
   |           |                                   |
  T1   IP1,P1  |<-- TCP established connection --->| IP2,P2
   |           |                                   |
   |           |                                   |
   |   close() |--------------- FIN -------------->|
   |           |<----------- FIN + ACK ------------|
   |    -*-    |--------------- ACK -------------->|
   |     |     |                                   |
   |     |     |                                   |
   |     |     |                                   |
   |     |     |                                   |
   |     |     |                                   |
   | TIME-WAIT |                                   |
   |   (60s)   |                                   |
   |     |     |                                   |
  T2     |     |                                   |
   |     |     |                                   |
   |     |     |                                   |
   |    -*-    |                                   |
   |           |                                   |
  T3   IP1,P1  |<-- TCP established connection --->| IP2,P2
   |           |                                   |
(*) IP1,IP2はIPアドレス、P1,P2はポート番号

(注)本パラメーラを変更すると、システム上の全てのアプリケーションに影響がでます。TCPコネクション単位でTIME-WAIT状態のソケットを再利用できるようにするには、ソケットオプション(SO_REUSEADDR)を使用してください。

2 検証環境

2.1 ネットワーク構成

サーバとクライアントの2台構成です。図中のenp1s0はNICの名前です。

                               192.168.122.0/24
client(enp1s0) ------------------------------------------(enp1s0) server
            .177                                       .68

2.2 版数

サーバとクライアントのAlmaLinuxの版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 8.6 (Sky Tiger)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
4.18.0-372.9.1.el8.x86_64

3 事前準備

クライアントからサーバの11111番ポートにアクセスできるようにするため、TCPの11111番ポートを解放します。なお、firewall-cmdコマンドの使い方は、firewall-cmdの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# firewall-cmd --add-port=11111/tcp

設定を確認します。11111番ポートへのアクセスを許可するルールが追加されたことがわかります。

[root@server ~]# firewall-cmd --list-ports
11111/tcp

カーネルパラメータ(ip_local_port_range)を変更して、クライアントのncプロセスが常に同じローカルポートを使用できるようにします。ここでは、ncプロセスが50001番のローカルポートを使用できるようにします。なお、ip_local_port_rangeの使い方は、カーネルパラメータの使い方(ip_local_port_range編) - hana_shinのLinux技術ブログを参照してください。

[root@client ~]# sysctl -w net.ipv4.ip_local_port_range="50001 50001"
net.ipv4.ip_local_port_range = 50001 50001

変更したカーネルパラメータの値を確認します。

[root@client ~]# sysctl -n net.ipv4.ip_local_port_range
50001   50001

4 tcp_tw_reuseが2の場合(デフォルト時)の動作確認

tcp_tw_reuseのデフォルト値は以下のとおりです。

[root@client ~]# sysctl -n net.ipv4.tcp_tw_reuse
2

サーバでncコマンドを実行します。なお、ncコマンドのインストール方法、使い方は、ncコマンドの使い方(ネットワーク実験の幅が広がるなぁ~) - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# nc -kl 11111

クライアントでncコマンドを実行します。ncコマンドを実行すると、サーバ/クライアント間でTCPコネクションが確立されます。

[root@client ~]# nc 192.168.122.68 11111

クライアントでssコマンドを実行します。サーバ/クライアント間でTCPコネクションが確立されていることがわかります(ssコマンド実行結果の一番下の行)。そして、ncプロセスが使用しているローカルポート番号が50001であることがわかります。なお、ssコマンドの使い方は、ssコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@client ~]# ss -natop4
State	Recv-Q	Send-Q	Local	Address:Port	Peer	Address:Port	Process
LISTEN	0	128	0.0.0.0:22	0.0.0.0:*	users:(("sshd",pid=830,fd=5))
ESTAB	0	0	192.168.122.177:22	192.168.122.1:60012	users:(("sshd",pid=1529,fd=5),("sshd",pid=1525,fd=5))	timer:(keepalive,88min,0)
ESTAB	0	0	192.168.122.177:22	192.168.122.1:59994	users:(("sshd",pid=1437,fd=5),("sshd",pid=1421,fd=5))	timer:(keepalive,44min,0)
ESTAB	0	0	192.168.122.177:50001	192.168.122.68:11111	users:(("nc",pid=1600,fd=3))

Ctrl+cを押下して、ncコマンドを終了します。

[root@client ~]# nc 192.168.122.68 11111
^C

ncコマンドの終了直後、ssコマンドを実行します。ソケットの状態を確認するとTIME-WAIT状態の残り時間が58秒であることがわかります。

[root@client ~]# ss -natop4
State     Recv-Q Send-Q   Local Address:Port     Peer Address:Port  Process
LISTEN    0      128            0.0.0.0:22            0.0.0.0:*      users:(("sshd",pid=830,fd=5))
ESTAB     0      0      192.168.122.177:22      192.168.122.1:60012  users:(("sshd",pid=1529,fd=5),("sshd",pid=1525,fd=5)) timer:(keepalive,98min,0)
ESTAB     0      0      192.168.122.177:22      192.168.122.1:59994  users:(("sshd",pid=1437,fd=5),("sshd",pid=1421,fd=5)) timer:(keepalive,54min,0)
TIME-WAIT 0      0      192.168.122.177:50001  192.168.122.68:11111  timer:(timewait,58sec,0)

ssコマンド実行直後、クライアントでncコマンドを実行します。TCPの状態がTIME-WAITなので、ncコマンドが終了してしまいます。TIME-WAIT状態のときは、ncコマンド終了直前に使用していたローカルポートを使ってTCPコネクションを確立することができないことがわかります。

[root@client ~]# nc 192.168.122.68 11111
[root@client ~]#

Ctrl+cを押下して60秒経過したあとssコマンドを実行します。60秒経過したのでTCPの状態がTIME-WAITのソケットがなくなったことがわかります。

[root@client ~]# ss -natop4
State   Recv-Q  Send-Q     Local Address:Port    Peer Address:Port  Process
LISTEN  0       128              0.0.0.0:22           0.0.0.0:*      users:(("sshd",pid=830,fd=5))
ESTAB   0       0        192.168.122.177:22     192.168.122.1:60012  users:(("sshd",pid=1529,fd=5),("sshd",pid=1525,fd=5)) timer:(keepalive,97min,0)
ESTAB   0       0        192.168.122.177:22     192.168.122.1:59994  users:(("sshd",pid=1437,fd=5),("sshd",pid=1421,fd=5)) timer:(keepalive,53min,0)

再度、ncコマンドを実行します。サーバとTCPコネクションを確立できることがわかります。

[root@client ~]# nc 192.168.122.68 11111

5 tcp_tw_reuseが1の場合の動作確認

TIME-WAIT状態のソケットを利用できるように、カーネルパラメータを変更します。

[root@client ~]# sysctl -w net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_reuse = 1

設定変更したカーネルパラメータの値を確認します。

[root@client ~]# sysctl -n net.ipv4.tcp_tw_reuse
1

サーバでncコマンドを実行します。

[root@server ~]# nc -kl 11111

クライアントでssコマンドを実行します。

[root@client ~]# nc 192.168.122.68 11111

クライアントでssコマンドを実行します。サーバ/クライアント間でTCPコネクションが確立されていることがわかります(ssコマンド実行結果の一番上の行)。

[root@client ~]# ss -nato4
State   Recv-Q  Send-Q     Local Address:Port      Peer Address:Port   Process
LISTEN  0       128              0.0.0.0:22             0.0.0.0:*
ESTAB   0       0        192.168.122.177:50001   192.168.122.68:11111
ESTAB   0       0        192.168.122.177:22       192.168.122.1:48296   timer:(keepalive,98min,0)
ESTAB   0       0        192.168.122.177:22       192.168.122.1:48298   timer:(keepalive,102min,0)

Ctrl+cを押下して、ncコマンドを終了します。

[root@client ~]# nc 192.168.122.68 11111
^C

ncコマンドの終了直後、ssコマンドを実行します。ソケットの状態を確認するとTCPがTIME-WAIT状態で、残り時間が58秒であることがわかります。

[root@client ~]# ss -nato4
State     Recv-Q  Send-Q     Local Address:Port      Peer Address:Port  Process
LISTEN    0       128              0.0.0.0:22             0.0.0.0:*
TIME-WAIT 0       0        192.168.122.177:50001   192.168.122.68:11111  timer:(timewait,58sec,0)
ESTAB     0       0        192.168.122.177:22       192.168.122.1:48296  timer:(keepalive,95min,0)
ESTAB     0       0        192.168.122.177:22       192.168.122.1:48298  timer:(keepalive,99min,0)

ssコマンド実行直後、クライアントでncコマンドを実行します。今度は、tcp_tw_reuseが有効になっているため、サーバ/クライアント間でTCPコネクションが確立できることがわかります。

[root@client ~]# nc 192.168.122.68 11111

クライアントでssコマンドを実行します。サーバ/クライアント間でTCPコネクションが確立されていることがわかります(ssコマンド実行結果の一番上の行)。

[root@client ~]# ss -nato4
State   Recv-Q  Send-Q     Local Address:Port      Peer Address:Port   Process
LISTEN  0       128              0.0.0.0:22             0.0.0.0:*
ESTAB   0       0        192.168.122.177:50001   192.168.122.68:11111
ESTAB   0       0        192.168.122.177:22       192.168.122.1:48296   timer:(keepalive,95min,0)
ESTAB   0       0        192.168.122.177:22       192.168.122.1:48298   timer:(keepalive,99min,0)

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ
TCPの状態遷移については、TCPの各種状態の作り方 - hana_shinのLinux技術ブログを参照してください。