在优化网络性能时, 不可避免要对网络的带宽进行测试. 通常大家可能都会使用iperf
来执行网络链路的吞吐量测试, 但iperf
只能测试TCP/IP
协议层的速度, 这个带宽数据跟TCP/UDP
协议的参数配置以及应用层缓冲区的大小都有关系. 有时, 我们希望直接测试网卡本身的实际吞吐量, 看看网卡实际的发包能力. Linux内核提供了pktgen
工具用以产生数据包, 向网卡注入TCP/UDP
数据. 这里, 我们就来看下具体如何通过pktgen
来测试网卡性能.
模块配置/加载 pktgen
在内核中是以模块的形式编译的, 使用之前确保内核配置了CONFIG_NET_PKTGEN
; 如果CONFIG_NET_PKTGEN
配置为m
, 则使用时需要modprobe pktgen
先加载模块. 模块加载完成后, 我们可以在/proc/net/pktgen
下面看到有如下几个目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ~# ls -al /proc/net/pktgen/ total 0 dr-xr-xr-x 2 root root 0 Mar 22 10 :57 . dr-xr-xr-x 6 root root 0 Mar 22 10 :57 .. -rw------- 1 root root 0 Mar 22 10 :57 kpktgend_0 -rw------- 1 root root 0 Mar 22 10 :57 kpktgend_1 -rw------- 1 root root 0 Mar 22 10 :57 kpktgend_2 -rw------- 1 root root 0 Mar 22 10 :57 kpktgend_3 -rw------- 1 root root 0 Mar 22 10 :57 kpktgend_4 -rw------- 1 root root 0 Mar 22 10 :57 kpktgend_5 -rw------- 1 root root 0 Mar 22 10 :57 kpktgend_6 -rw------- 1 root root 0 Mar 22 10 :57 kpktgend_7 -rw------- 1 root root 0 Mar 22 10 :57 pgctrl
其中kpktgend_*
是内核数据包生产线程, 每个CPU都会启动一个相应的线程, 如果要添加某个测试网卡, 可以通过向该文件节点写入add_device ethX
; pgctrl
用于控制网卡性能测试状态需要在对应的线程执行网卡的吞吐量测试, 有start
/stop
/reset
三种状态.
更多pktgen
的信息可以参考内核文档pktgen.txt
以及源代码pktgen.c
脚本测试 刚开始碰到pktgen
测试网卡, 会被一堆参数搞得头晕, 好在内核的代码示例已经有了一些基本的脚本, 我们只需要根据自己的需要稍加改造就可以用起来了, 具体可以参考内核源码目录samples/pktgen
. 下面贴了一段用于配置/启动测试的脚本, 完整的代码示例可以参考pktgen_test.sh .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 pg_ctrl "reset" for (( thread = 0; thread < $THREADS ; ++thread )); do PGDEV=${DEV} @$thread echo "Removing all devices" pg_thread $thread "rem_device_all" echo "Adding eth0" pg_thread $thread "add_device $PGDEV " pg_set $PGDEV "flag QUEUE_MAP_CPU" CLONE_SKB="clone_skb 000000" echo "Configuring $PGDEV " pg_set $PGDEV "count 10000000" pg_set $PGDEV "clone_skb 000000" pg_set $PGDEV "pkt_size $PKT_SIZE " pg_set $PGDEV "delay 0" pg_set $PGDEV "dst $DEST_IP " pg_set $PGDEV "dst_mac $DEST_MAC " done echo "Running... ctrl^C to stop" trap pg_stop SIGINTpg_ctrl "start" echo "Done" for ((thread = 0; thread < $THREADS ; thread++)); do dev=${DEV} @${thread} echo "Device: $dev " cat /proc/net/pktgen/$dev | grep -A2 "Result:" done
这个脚本总体说来主要分为三个步骤:
pg_ctrl "reset"
: 清除上一次测试状态
pg_thread $thread "add_device $PGDEV"
: 配置测试的网卡
pg_ctrl "start"
: 开启测试, 按ctrl+C
后, 进程退出, 内核结束发包
比如, 执行./pktgen_test.sh -i enp0s31f6 -d 10.193.200.1 -m 31:b6:89:55:b3:8c -t 2
(使用两个内核线程发包), 测试结束后, 会打印出测试结果(实际查看/proc/net/pktgen/enp0s31f6*
的结果会输出更多信息, 脚本里对输出做了过滤), 包括测试的时间/是否出现错误以及吞吐量:
1 2 3 4 5 6 7 8 Device: enp0s31f6@0 Result: OK: 1662287 (c1662114+d172) usec, 89218 (1024b yte,0f rags) 53671 pps 439 Mb/sec (439672832b ps) errors: 0 Device: enp0s31f6@1 Result: OK: 1606214 (c1605962+d252) usec, 108442 (1024b yte,0f rags) 67514 pps 553 Mb/sec (553074688b ps) errors: 0
从上面可以看到, 网卡的PPS
(Packet Per Second
)大约在121185
(1.2Mpps), 带宽在992Mb/s
, 这个速度已经比较接近于千兆网卡的理论吞吐量1.5Mpps
(1000bps/((64 + 20)*8))了(这里64B为以太网数据帧的最小尺寸, 46(pad) + 14(dmac,smac,type) + 4(CRC)
, 20B 为以太网帧前导和帧间距的大小).
参考资料