Help us understand the problem. What is going on with this article?

TSO(TCP Segmentation Offload)について

1 はじめに

TSOは、NICが送信パケットをMTU長に分割する仕組みです。
以前は、カーネルで分割していましたが、最近はNICでパケットを分割することができます。
NICでパケットを分割することでカーネルの負荷を低減することができます。

ここでは、仮想NICのTSOが有効/無効時、送信パケットがtcpdumpでどのように見えるか、
確認してみました。

ところで、仮想NICでTSOを有効にすることに意味があるのか良くわかっていません。
個人的には、意味がないと思うのでが、各種実験をする際、役にたつので試してみました。
私の環境では、デフォルトは仮想NICのTSOは有効です。

2 環境

2.1 ネットワーク構成

VMware Workstation 14 Playerで作成した仮想マシン(2台)を使用しました。
client,serverはホスト名です。

ネットワーク構成
                     192.168.3.0/24
      .30                                  .20
client ------------------------------------- server 

2.2 MTU(Maximum Transmission Unit)

サーバ(eth0)のMTUは1500です。

サーバのMTU
[root@server ~]# ip l show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:35:6b:42 brd ff:ff:ff:ff:ff:ff

クライアント(eth0)のMTUは1500です。

クライアントのMTU
[root@client ~]# ip l show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:26:c1:e3 brd ff:ff:ff:ff:ff:ff

2.3 hostsファイル

サーバ、クライアントのhostsファイルは以下のようになっています。

hostsファイル
[root@server ~]# cat /etc/hosts
-snip-
192.168.3.20 server
192.168.3.30 client

2.4 OS版数

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

OS版数
[root@server ~]# cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)

[root@server ~]# uname -r
3.10.0-957.el7.x86_64

3 事前準備

サーバのTCP/11111番ポートを使用するので、TCP/11111番ポートへのアクセスを許可します。

なお、firewall-cmdの使い方は、ここ(firewall-cmdコマンドの使い方)を参照してください。

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

4 TSO有効時

仮想NICのTSOを確認します。TSOが有効であることがわかります。
なお、指定するオプション-kは小文字です。

TSO確認
[root@client ~]# ethtool -k eth0|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: on

クライアントでtcpdumpを起動します。
送信元/送信先ポート番号ともにTCP/11111番ポートを指定します。
なお、tcpdumpの使い方は、ここ(tcpdumpの使い方)を参照してください。

[root@client ~]#  tcpdump -i eth0 port 11111

クライアントからサーバに送信する送信パケットのデータを作成します。
データサイズは2000(byte)とします。

[root@client ~]# fallocate -l 2000 test.dat
[root@client ~]# ls -l test.dat
-rw-r--r--. 1 root root 2000  9月 23 18:40 test.dat

サーバ側は、TCPの11111番ポートでListenします。
なお、ncコマンドは、ここ(ncコマンドの使い方)を参照してください。

[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で採取した送信パケットのサイズは、2000(byte)になっていることがわかります(★印)。

[root@client ~]#  tcpdump -i eth0 port 11111
-snip-
18:42:26.662384 IP client.46226 > server.vce: Flags [S], seq 881434201, win 29200, options [mss 1460,sackOK,TS val 6220325 ecr 0,nop,wscale 7], length 0
18:42:26.662871 IP server.vce > client.46226: Flags [S.], seq 2625670731, ack 881434202, win 28960, options [mss 1460,sackOK,TS val 3902545 ecr 6220325,nop,wscale 7], length 0
18:42:26.662951 IP client.46226 > server.vce: Flags [.], ack 1, win 229, options [nop,nop,TS val 6220326 ecr 3902545], length 0
18:42:26.663349 IP client.46226 > server.vce: Flags [P.], seq 1:2001, ack 1, win 229, options [nop,nop,TS val 6220326 ecr 3902545], ★length 2000
18:42:26.663520 IP client.46226 > server.vce: Flags [F.], seq 2001, ack 1, win 229, options [nop,nop,TS val 6220326 ecr 3902545], length 0
18:42:26.663594 IP server.vce > client.46226: Flags [.], ack 2001, win 258, options [nop,nop,TS val 3902545 ecr 6220326], length 0
18:42:26.663906 IP server.vce > client.46226: Flags [F.], seq 1, ack 2002, win 258, options [nop,nop,TS val 3902546 ecr 6220326], length 0
18:42:26.663945 IP client.46226 > server.vce: Flags [.], ack 2, win 229, options [nop,nop,TS val 6220327 ecr 3902546], length 0

5 TSO無効時

eth0のTSOを無効にします。つまり、カーネルで送信パケットを分割します。
なお、指定するオプション-Kは大文字です。

TSOの無効化
[root@client ~]# ethtool -K eth0 tso off

eth0のTSOを確認します。TSOが無効になったことがわかります。
なお、指定するオプション-kは小文字です。

TSOの確認
[root@client ~]# ethtool -k eth0|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を起動します。
送信元/送信先ポート番号ともにTCP/11111番ポートを指定します。

[root@client ~]#  tcpdump -i eth0 port 11111

サーバ側は、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

送信パケットが、1448(byte)と552(byte)に分割されていることがわかります(★印)。

[root@client ~]#  tcpdump -i eth0 port 11111
-snip-
18:54:01.105588 IP client.46228 > server.vce: Flags [S], seq 3382614099, win 29200, options [mss 1460,sackOK,TS val 6914768 ecr 0,nop,wscale 7], length 0
18:54:01.106210 IP server.vce > client.46228: Flags [S.], seq 777124350, ack 3382614100, win 28960, options [mss 1460,sackOK,TS val 4596988 ecr 6914768,nop,wscale 7], length 0
18:54:01.106255 IP client.46228 > server.vce: Flags [.], ack 1, win 229, options [nop,nop,TS val 6914769 ecr 4596988], length 0
18:54:01.106843 IP client.46228 > server.vce: Flags [.], seq 1:1449, ack 1, win 229, options [nop,nop,TS val 6914770 ecr 4596988], ★length 1448
18:54:01.106848 IP client.46228 > server.vce: Flags [P.], seq 1449:2001, ack 1, win 229, options [nop,nop,TS val 6914770 ecr 4596988], ★length 552
18:54:01.106976 IP client.46228 > server.vce: Flags [F.], seq 2001, ack 1, win 229, options [nop,nop,TS val 6914770 ecr 4596988], length 0
18:54:01.107118 IP server.vce > client.46228: Flags [.], ack 2001, win 258, options [nop,nop,TS val 4596989 ecr 6914770], length 0
18:54:01.107306 IP server.vce > client.46228: Flags [F.], seq 1, ack 2002, win 258, options [nop,nop,TS val 4596989 ecr 6914770], length 0
18:54:01.107360 IP client.46228 > server.vce: Flags [.], ack 2, win 229, options [nop,nop,TS val 6914770 ecr 4596989], length 0

6 まとめ

・NICのTSOが有効:NICでパケット分割
・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オプションが付加されます。

7 補足

tcpdumpがパケットをキャプチャするのは、カーネルとdriverの間です。
送信パケットはdev_queue_xmit_nit 、受信パケットはtpacket_rcvでキャプチャします。

構成
+---------------------+
|       kernel        |
+---------------------+
|      tcpdump        |
+---------------------+
|       driver        |
+---------------------+
|       NIC           |
+---------------------+
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away