hana_shinのLinux技術ブログ

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

stress-ngコマンドの使い方(UDP編)



1 はじめに

stress-ngコマンドは、CPU、メモリ、ディスク、ネットワークなど、さまざまなリソースに対して負荷テストを行うためのツールです。stressコマンドと比較して、より多くの種類のリソースに対して負荷をかけることができます。本記事ではUDPに関する使い方を説明します。なお、stressコマンド、およびstress-ngコマンドの基本的な使い方は、以下の記事を参照してください。

2 検証環境

AlmaLinuxの版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.2 (Turquoise Kodkod)

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

[root@server ~]# uname -r
5.14.0-284.11.1.el9_2.x86_64

3 パッケージのインストール方法

stress-ngパッケージをインストールします。なお、dnfコマンドの使い方は、dnfコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# dnf -y install stress-ng

stress-ngコマンドの版数を確認します。

[root@server ~]# stress-ng -V
stress-ng, version 0.15.00 (gcc 11.3, x86_64 Linux 5.14.0-284.11.1.el9_2.x86_64) ?諮

なお、AlmaLinux 9.1以前は、stress-ngパッケージはepelリポジトリにあるので、まずepel-releaseパッケージをインストールします。そのあと、stress-ngパッケージをインストールします。

[root@server ~]# dnf -y install epel-release
[root@server ~]# dnf -y install stress-ng

4 オプション一覧

stress-ngコマンドのUDPオプションには以下のものがあります。

[root@server ~]# man stress-ng
-snip-
       --udp N
              start  N workers that transmit data using UDP. This involves a pair of client/server processes perform‐
              ing rapid connect, send and receives and disconnects on the local host.

       --udp-domain D
              specify the domain to use, the default is ipv4. Currently ipv4, ipv6 and unix are supported.

       --udp-if NAME
              use network interface NAME. If the interface NAME does not exist, is not up or does not support the do‐
              main then the loopback (lo) interface is used as the default.

       --udp-gro
              enable UDP-GRO (Generic Receive Offload) if supported.

       --udp-lite
              use the UDP-Lite (RFC 3828) protocol (only for ipv4 and ipv6 domains).

       --udp-ops N
              stop udp stress workers after N bogo operations.

       --udp-port P
              start  at port P. For N udp worker processes, ports P to P - 1 are used. By default, ports 7000 upwards
              are used.

       --udp-flood N
              start N workers that attempt to flood the host with UDP packets to random ports. The IP address of  the
              packets are currently not spoofed. This is only available on systems that support AF_PACKET.

       --udp-flood-domain D
              specify the domain to use, the default is ipv4. Currently ipv4 and ipv6 are supported.

       --udp-flood-if NAME
              use network interface NAME. If the interface NAME does not exist, is not up or does not support the do‐
              main then the loopback (lo) interface is used as the default.

       --udp-flood-ops N
              stop udp-flood stress workers after N bogo operations.

5 送受信のプロセス数を指定する方法(--udp)

--udpオプションは、UDPパケットの送受信プロセス数を指定するためのオプションです。1を指定すると、送受信プロセスがそれぞれ1つずつ生成されます。2を指定すると、送受信プロセスがそれぞれ2つずつ生成されます。あとは同様です。また、-kオプションは、親プロセスと子プロセスを同じ名前にするためのオプションです。psコマンドの実行結果を見ると、全てのプロセスの名前がstress-ngであることがわかります。

[root@server ~]# stress-ng -k --udp 1
stress-ng: info:  [1541] defaulting to a 86400 second (1 day, 0.00 secs) run per stressor
stress-ng: info:  [1541] dispatching hogs: 1 udp

psコマンドを使用してプロセスの状態を確認します。また、後述するstraceコマンドの実行結果から分かるように、PID=1542はUDPパケットの受信プロセス、PID=1543はUDPパケットの送信プロセスです。また、PID=1541は送受信プロセスの終了をwaitシステムコールで待機しています。do_waitはwaitシステムコールの延長として呼び出されるカーネル関数です。なお、psコマンドの使い方は、psコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# ps -C stress-ng -o comm,pid,ppid,psr,%cpu,wchan
COMMAND             PID    PPID PSR %CPU WCHAN
stress-ng          1541    1515   3  0.0 do_wait
stress-ng          1542    1541   1 43.5 -
stress-ng          1543    1542   3 49.7 -

次に、lsofコマンドを実行します。PID=1542はUDPパケットの受信プロセスです。UDPの7000番ポートで受信待ちしていることがわかります。そして、PID=1543はUDPパケットの送信プロセスです。UDPパケットをポート番号60301から送信します。また、それぞれのプロセスは、任意のIPアドレス(ポート番号の前のIPアドレスワイルドカード(*)なので)でUDPパケットの送受信を実行することがわかります。なお、lsofコマンドの使い方は、lsofコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# lsof -c stress-ng -a -i -a -nP
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
stress-ng 1542 root    4u  IPv4  21463      0t0  UDP *:7000
stress-ng 1543 root    4u  IPv4  23423      0t0  UDP *:60301

PID=1543のプロセスに対して、straceコマンドを実行します。 PID=1543のプロセスはsendtoシステムコールを繰り返し実行しています。宛先UDPポート番号は7000、送信元IPアドレスは任意のIPアドレス(0.0.0.0)であることがわかります。なお、straceコマンドの使い方は、straceコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]#  strace -e trace=network -p 1543
strace: Process 1543 attached
sendto(4, "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"..., 304, 0, {sa_family=AF_INET, sin_port=htons(7000), sin_addr=inet_addr("0.0.0.0")}, 16) = 304
sendto(4, "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"..., 320, 0, {sa_family=AF_INET, sin_port=htons(7000), sin_addr=inet_addr("0.0.0.0")}, 16) = 320
sendto(4, "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"..., 336, 0, {sa_family=AF_INET, sin_port=htons(7000), sin_addr=inet_addr("0.0.0.0")}, 16) = 336
-snip-

PID=1542のプロセスに対して、straceコマンドを実行します。PID=1542のプロセスはrecvfromシステムコールを繰り返し実行しています。送信元UDPポート番号は60301、送信元IPアドレス127.0.0.1であることがわかります。

[root@server ~]#  strace -e trace=network -p 1542
strace: Process 1542 attached
recvfrom(4, "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(60301), sin_addr=inet_addr("127.0.0.1")}, [16]) = 960
recvfrom(4, "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(60301), sin_addr=inet_addr("127.0.0.1")}, [16]) = 976
recvfrom(4, "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(60301), sin_addr=inet_addr("127.0.0.1")}, [16]) = 992
recvfrom(4, "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(60301), sin_addr=inet_addr("127.0.0.1")}, [16]) = 1008
-snip-

tcpdumpコマンドを実行すると、loデバイスを介してUDPパケットを送受信していることがわかります。なお、tcpdumpコマンドの使い方は、tcpdumpの使い方(基本編) - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# tcpdump -i lo -nn
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:01:24.361797 IP 127.0.0.1.60301 > 127.0.0.1.7000:  rx type 86 (480)
20:01:24.361805 IP 127.0.0.1.60301 > 127.0.0.1.7000:  rx type 87 (496)
20:01:24.361813 IP 127.0.0.1.60301 > 127.0.0.1.7000:  rx type 88 (512)
-snip-

Ctrl+cを押下してstress-ngコマンドを終了します。

[root@server ~]# stress-ng -k --udp 1
stress-ng: info:  [1541] defaulting to a 86400 second (1 day, 0.00 secs) run per stressor
stress-ng: info:  [1541] dispatching hogs: 1 udp
^Cstress-ng: info:  [1541] successful run completed in 653.52s (10 mins, 53.52 secs)

6 受信待ちのポート番号を指定する方法(--udp-port)

--udp-port オプションは、UDPパケットの到着を待ち受けるポート番号を指定するためのオプションです。デフォルトではポート番号7000が使用されますが、もし他のプロセスが同じポート番号(7000)をすでに使用している場合、このオプションを使用して、stress-ngプロセスの受信ポート番号を変更することができます。

[root@server ~]# stress-ng -k --udp 1 --udp-port 8000
stress-ng: info:  [1790] defaulting to a 86400 second (1 day, 0.00 secs) run per stressor
stress-ng: info:  [1790] dispatching hogs: 1 udp

lsofコマンドを実行すると、stress-ngプロセスが8000番ポートでUDPパケットの受信待ちをしていることが確認できます。

[root@server ~]# lsof -c stress-ng -a -i -a -nP
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
stress-ng 1791 root    4u  IPv4  25883      0t0  UDP *:8000
stress-ng 1792 root    4u  IPv4  23820      0t0  UDP *:48625

7 IPv4またはIPv6を指定する方法(--udp-domain)

--udp-domainオプションは、UDPパケットの送受信において、IPv4またはIPv6を使用するかを指定するオプションです。デフォルトでは、UDPパケットの送受信にはIPv4が利用されますが、このオプションを使用することでIPv6を選択することが可能です

送受信するUDPパケットを確認するため、tcpdumpコマンドを実行します。

[root@server ~]# tcpdump -i lo -nn

--udp-domainオプションにipv6を指定して、stress-ngコマンドを実行します。

[root@server ~]# stress-ng -k --udp 1 --udp-domain ipv6
stress-ng: info:  [1314] defaulting to a 86400 second (1 day, 0.00 secs) run per stressor
stress-ng: info:  [1314] dispatching hogs: 1 udp
stress-ng: info:  [1314] successful run completed in 0.01s

送受信するUDPパケットを確認するため、tcpdumpコマンドを実行すると、ループバックアドレスIPv6UDPパケットが送受信されていることが確認できます。

[root@server ~]# tcpdump -i lo -nn
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:16:11.211740 IP6 ::1.60769 > ::1.7000:  [|rx] (16)
20:16:11.211915 IP6 ::1.60769 > ::1.7000:  rx type 66 (32)
20:16:11.211938 IP6 ::1.60769 > ::1.7000:  rx type 67 (48)
20:16:11.211958 IP6 ::1.60769 > ::1.7000:  rx type 68 (64)
-snip-

8 実行回数を指定する方法(--udp-ops)

--udp-opsUDPパケットの送信回数を指定するオプションです。

UDPパケットを5回送信してみます。

[root@server ~]# stress-ng -k --udp 1 --udp-ops 5
stress-ng: info:  [1636] defaulting to a 86400 second (1 day, 0.00 secs) run per stressor
stress-ng: info:  [1636] dispatching hogs: 1 udp
stress-ng: info:  [1636] successful run completed in 0.00s

tcpdumpコマンドの実行結果を確認すると、UDPパケットが5回送信されているのがわかります。

[root@server ~]# tcpdump -i lo -nn
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:24:55.105270 IP 127.0.0.1.47176 > 127.0.0.1.7000:  [|rx] (16)
20:24:55.105338 IP 127.0.0.1.47176 > 127.0.0.1.7000:  rx type 66 (32)
20:24:55.105361 IP 127.0.0.1.47176 > 127.0.0.1.7000:  rx type 67 (48)
20:24:55.105380 IP 127.0.0.1.47176 > 127.0.0.1.7000:  rx type 68 (64)
20:24:55.105398 IP 127.0.0.1.47176 > 127.0.0.1.7000:  rx type 69 (80)

9 UDPパケット送受信するインタフェースを指定する方法(--udp-if)

--udp-ifオプションは、UDPパケットの送受信に使用するインタフェースを指定するオプションですが、実験をしてみると正常に機能していないようにみえます。

--udp-ifオプションにeth0を指定してstress-ngコマンドを実行します。

[root@server ~]# stress-ng -k --udp 1 --udp-if eth0 --udp-ops 3
stress-ng: info:  [1235] defaulting to a 86400 second (1 day, 0.00 secs) run per stressor
stress-ng: info:  [1235] dispatching hogs: 1 udp
stress-ng: info:  [1235] successful run completed in 0.01s

tcpdumpコマンドの実行結果を確認すると、インタフェースにeth0を指定したにもかかわらず、lo(127.0.0.1)を使用しています。

[root@server ~]# tcpdump -i any udp port 7000 -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:03:14.857652 lo    In  IP 127.0.0.1.51858 > 127.0.0.1.7000:  [|rx] (16)
20:03:14.857752 lo    In  IP 127.0.0.1.51858 > 127.0.0.1.7000:  rx type 66 (32)
20:03:14.857768 lo    In  IP 127.0.0.1.51858 > 127.0.0.1.7000:  rx type 67 (48)
20:03:14.857779 lo    In  IP 127.0.0.1.51858 > 127.0.0.1.7000:  rx type 68 (64)
20:03:14.857789 lo    In  IP 127.0.0.1.51858 > 127.0.0.1.7000:  rx type 69 (80)
-snip-

10 受信待ちのポート番号をランダムに指定する方法(--udp-flood)

--udp-floodオプションは、UDPパケットの受信ポート番号をランダムに指定するオプションです。

送受信するUDPパケットを確認するため、tcpdumpコマンドを実行します。

[root@server ~]# tcpdump -i any udp -nn

stress-ngコマンドを実行します。

[root@server ~]# stress-ng -k --udp-flood 1 --udp-flood-ops 3
stress-ng: info:  [1273] defaulting to a 86400 second (1 day, 0.00 secs) run per stressor
stress-ng: info:  [1273] dispatching hogs: 1 udp-flood
stress-ng: info:  [1273] successful run completed in 0.00s

tcpdumpコマンドの実行結果を確認すると、UDPパケットの受信ポート番号が1025,31282,1026と変化していることがわかります。

[root@server ~]# tcpdump -i any udp -nn
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:14:23.005442 lo    In  IP 127.0.0.1.36690 > 127.0.0.1.1025: UDP, length 1
20:14:23.005498 lo    In  IP 127.0.0.1.36690 > 127.0.0.1.31282: UDP, length 1
20:14:23.005543 lo    In  IP 127.0.0.1.36690 > 127.0.0.1.1026: UDP, length 2

11 UDP-Liteのパケットを送受信する方法(--udp-lite)

私の環境では、CONFIG_UDPLITEが定義されていないので、実験することができませんでした。

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ