1 TSO(TCP Segmentation Offload)とは?
TSOは、NICが送信パケットをMTU長に分割する仕組みです。以前は、カーネルで分割していましたが、最近はNICでパケットを分割することができます。NICでパケットを分割することで、カーネルのCPU負荷を低減することができます。ここでは、仮想NICのTSOが有効/無効の時、TCPパケットがどのように分割されるかを確認してみます。
2 検証環境
2.1 ネットワーク構成
サーバとクライアントの2台構成です。図中のens33はNICの名前です。
192.168.2.0/24 client(ens33) -------------------------------------(ens33) server .105 .100
2.2 版数
サーバ、クライアントともに下記版数です。
[root@server ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core)
カーネル版数は以下のとおりです。
[root@server ~]# uname -r 3.10.0-1160.el7.x86_64
3 事前準備
サーバのTCP/11111番ポートを使用するので、TCP/11111番ポートへのアクセスを許可します。firewall-cmdコマンドの使い方は、firewall-cmdの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# firewall-cmd --add-port=11111/tcp success
ポートの状態を確認します。11111番ポートが開放されたことがわかります。
[root@server ~]# firewall-cmd --list-ports 11111/tcp
4 TSO有効時
仮想NICのTSOを確認します。TSOが有効(★)であることがわかります。なお、指定するオプション-kは小文字です。
[root@client ~]# ethtool -k ens33 | grep tcp tcp-segmentation-offload: on ★ tx-tcp-segmentation: on tx-tcp-ecn-segmentation: off [fixed] tx-tcp6-segmentation: off [fixed] tx-tcp-mangleid-segmentation: off
クライアントからサーバに送信する送信データを作成します。データサイズは2000(byte)とします。送信データの作成方法は、ファイルの作り方 - hana_shinのLinux技術ブログを参照してください。
[root@client ~]# fallocate -l 2000 test.dat [root@client ~]# ls -l test.dat -rw-r--r--. 1 root root 2000 1月 14 21:25 test.dat
クライアントでtcpdumpを実行します。tcpdumpの使い方は、tcpdumpの使い方(基本編) - hana_shinのLinux技術ブログを参照してください。
[root@client ~]# tcpdump -i ens33 port 11111 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
サーバでncコマンドを実行します。ncプロセスがTCPの11111番ポートでListenするようにします。ncコマンドは、ncコマンドの使い方(ネットワーク実験の幅が広がるなぁ~) - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# nc -klv 11111 > test.dat Ncat: Version 7.50 ( https://nmap.org/ncat ) Ncat: Listening on :::11111 Ncat: Listening on 0.0.0.0:11111
ncプロセスがListenしているポート番号を確認します。TCPの11111番ポートでListenしていることがわかります。lsofコマンドは、lsofコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# lsof -c nc -a -i4 -a -P COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 3964 root 4u IPv4 55566 0t0 TCP *:11111 (LISTEN)
クライアントからサーバにデータを送信します。
[root@client ~]# nc server 11111 < test.dat
tcpdumpの実行結果を確認します。tcpdumpは、カーネルとNICの間でパケットをキャプチャします。TSOが有効なので、TCP層ではなくNICでパケットの分割をするので、TCPパケットのペイロードサイズが2000(byte)と表示されています。
[root@client ~]# tcpdump -i ens33 port 11111 -nn tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes 21:32:08.742695 IP 192.168.2.105.57310 > 192.168.2.100.11111: Flags [S], seq 3702008934, win 29200, options [mss 1460,sackOK,TS val 474675 ecr 0,nop,wscale 7], length 0 21:32:08.743483 IP 192.168.2.100.11111 > 192.168.2.105.57310: Flags [S.], seq 2914285991, ack 3702008935, win 28960, options [mss 1460,sackOK,TS val 9891545 ecr 474675,nop,wscale 7], length 0 21:32:08.743560 IP 192.168.2.105.57310 > 192.168.2.100.11111: Flags [.], ack 1, win 229, options [nop,nop,TS val 474676 ecr 9891545], length 0 21:32:08.743731 IP 192.168.2.105.57310 > 192.168.2.100.11111: Flags [P.], seq 1:2001, ack 1, win 229, options [nop,nop,TS val 474676 ecr 9891545], length 2000 ★ 21:32:08.743861 IP 192.168.2.105.57310 > 192.168.2.100.11111: Flags [F.], seq 2001, ack 1, win 229, options [nop,nop,TS val 474676 ecr 9891545], length 0 21:32:08.744240 IP 192.168.2.100.11111 > 192.168.2.105.57310: Flags [.], ack 2001, win 258, options [nop,nop,TS val 9891546 ecr 474676], length 0 21:32:08.744287 IP 192.168.2.100.11111 > 192.168.2.105.57310: Flags [F.], seq 1, ack 2002, win 258, options [nop,nop,TS val 9891546 ecr 474676], length 0 21:32:08.744394 IP 192.168.2.105.57310 > 192.168.2.100.11111: Flags [.], ack 2, win 229, options [nop,nop,TS val 474677 ecr 9891546], length 0
5 TSO無効時
ens33のTSOを無効にします。つまり、カーネルで送信パケットを分割することになります。なお、指定するオプション-Kは大文字です。
[root@client ~]# ethtool -K ens33 tso off
TSOの設定有無を確認します。TSOが無効(★)になったことがわかります。なお、指定するオプション-kは小文字です。
[root@client ~]# ethtool -k ens33|grep tcp tcp-segmentation-offload: off ★ tx-tcp-segmentation: off tx-tcp-ecn-segmentation: off [fixed] tx-tcp6-segmentation: off [fixed] tx-tcp-mangleid-segmentation: off
クライアントでtcpdumpを実行します。
[root@client ~]# tcpdump -i ens33 port 11111 -nn tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
サーバでncコマンドを実行します。ncプロセスがTCPの11111番ポートでListenするようにします。
[root@server ~]# nc -klv 11111 > test.dat Ncat: Version 7.50 ( https://nmap.org/ncat ) Ncat: Listening on :::11111 Ncat: Listening on 0.0.0.0:11111
クライアントからサーバにデータを送信します。
[root@client ~]# nc server 11111 < test.dat
tcpdumpの実行結果を確認します。tcpdumpは、カーネルとNICの間でパケットをキャプチャします。TSOが無効なので、TCP層でパケットを分割をするので、TCPパケットのペイロードサイズが1448(byte)と552(byte)と表示されています。
[root@client ~]# tcpdump -i ens33 port 11111 -nn tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes 21:36:20.217351 IP 192.168.2.105.57312 > 192.168.2.100.11111: Flags [S], seq 3888141037, win 29200, options [mss 1460,sackOK,TS val 726136 ecr 0,nop,wscale 7], length 0 21:36:20.217964 IP 192.168.2.100.11111 > 192.168.2.105.57312: Flags [S.], seq 4173351009, ack 3888141038, win 28960, options [mss 1460,sackOK,TS val 10143024 ecr 726136,nop,wscale 7], length 0 21:36:20.218192 IP 192.168.2.105.57312 > 192.168.2.100.11111: Flags [.], ack 1, win 229, options [nop,nop,TS val 726150 ecr 10143024], length 0 21:36:20.218659 IP 192.168.2.105.57312 > 192.168.2.100.11111: Flags [.], seq 1:1449, ack 1, win 229, options [nop,nop,TS val 726151 ecr 10143024], length 1448 ★ 21:36:20.218666 IP 192.168.2.105.57312 > 192.168.2.100.11111: Flags [P.], seq 1449:2001, ack 1, win 229, options [nop,nop,TS val 726151 ecr 10143024], length 552 ★ 21:36:20.218673 IP 192.168.2.105.57312 > 192.168.2.100.11111: Flags [F.], seq 2001, ack 1, win 229, options [nop,nop,TS val 726151 ecr 10143024], length 0 21:36:20.219287 IP 192.168.2.100.11111 > 192.168.2.105.57312: Flags [.], ack 2001, win 258, options [nop,nop,TS val 10143025 ecr 726151], length 0 21:36:20.219782 IP 192.168.2.100.11111 > 192.168.2.105.57312: Flags [F.], seq 1, ack 2002, win 258, options [nop,nop,TS val 10143025 ecr 726151], length 0 21:36:20.219874 IP 192.168.2.105.57312 > 192.168.2.100.11111: Flags [.], ack 2, win 229, options [nop,nop,TS val 726152 ecr 10143025], length 0
6 まとめ
・TSOが有効の場合:NICでパケット分割
・TSOが無効の場合:カーネルでパケット分割
カーネルが分割するパケットサイズは、MTUからTCP/IPヘッダのサイズを引いた値になります。MTUはイーサネット環境では1500(byte)です。TCP/IPヘッダサイズは、各々20(byte)です。したがって、分割するパケットサイズは1460(byte)になります。しかし、最近はTCPヘッダに、TCPタイムスタンプオプション(12byte)が付くのが一般的です。したがって、分割するパケットサイズは、1448(byte)単位になります。なお、オプションヘッダを付けるかどうかは、3 way handshakeの時に決定します。TCPの両端がTCPオプションを付けることに合意すれば、TCPオプションが付加されます。
Z 参考情報
私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ