網上有很多講解pktgen的文章,但總是不夠全面細致,看完之后自己還是不會寫pktgen測試腳本,為此本文對pktgen進行詳細的闡述,讓大家看完本文后能夠自己動手寫pktgen shell.
1.pktgen簡介
pktgen是一個位於linux內核層的高性能網絡測試工具,由瑞士皇家理工大學的TSlab實驗室的Robert Olsson開發的(現在應該不在皇家理工了),主要用來測試網絡驅動與網卡設備,支持多線程,能夠產生隨機mac地址、IP地址、UDP端口號的數據包,pktgen 的作者使用多CPU處理器在不同的PCI總線(pci 、pcie等總線)上用千兆以太網卡做過測試(pktgen的表現依賴於CPU處理速率、內存延時、pci總線速率等硬件參數),發送數據速率甚至可以大於10GBit/s。可見是可以滿足大多數的網卡等測試需求。
pktgen的配置與統計信息查看都使用/proc文件系統完成,/proc文件系統是一種特殊的,有軟件創建的文件系統,內核使用/proc文件系統向外界導出信息,外界也可以通過它配置內核態的一些進程的參數,如ps top uptime等linux發行版中的很多工具就是通過/proc實現的.在大多情況下,我們只用/proc讀出數據(用於調試內核驅動等),而在pktgen中配置命令就用到了/proc的寫入數據功能。
2.使用pktgen進行發包實驗
現在版本的linux發行版大多加入了pktgen,使用以下命令加載pktgen模塊:
#modprobe pktgen
然后你將在你的電腦的/proc/net/pktgen看到以下文件:
kpktgend_0 kpktgend_1 kpktgend_2 kpktgend_3 pgctrl
其中kpktgen_*的多少是根據你的CPU的個數決定的,如我的機子的CPU數目為4,則有四個此文件。
通過命令cat /proc/net/pktgen/pgctrl可以查看pktgen的版本等信息:
#cat /proc/net/pktgen/pgctrl
Packet Generator for packet performance testing. Version: 2.74
2.1使用pktgen一些需要注意的地方
1)中斷親和力
當使用某個線程(kpktgend_x)通過某個端口(ethx)發送(接受)數據時,我們應該把這個端口所對應的中斷綁定到某一個CPU上,從而防止CPU的變動(操作系統引起的)導致CPU緩存的丟失。具體做法如下
首先,通過以下命令查看ethx所對應的中斷,在這里我們以eth3為例
# cat /proc/interrupts | grep eth3
47: 45836 0 0 0 PCI-MSI-edge eth3-TxRx-0
48: 45836 0 0 0 PCI-MSI-edge eth3-TxRx-1
49: 45836 0 0 0 PCI-MSI-edge eth3-TxRx-2
50: 45836 0 0 0 PCI-MSI-edge eth3-TxRx-3
51: 0 0 0 0 PCI-MSI-edge eth3:lsc
由上可以看出eth3使用了五個中斷號,為47-51,我們在這里將其都綁定在CPU0上
# echo 1 /proc/irq/47/smp_affinity # echo 1 /proc/irq/48/smp_affinity # echo 1 /proc/irq/49/smp_affinity # echo 1 /proc/irq/50/smp_affinity # echo 1 /proc/irq/51/smp_affinity
當然若你分開綁定的話,在大數據流的時候可以均攤CPU的負擔,可能對最高性能有所提升,具體就不清楚了,這個應該還和Intel網卡的多隊列相關了,有關分析有待進一步實驗。
Robert測試結果說明,正確的中斷親和力綁定,對發送速率有60%的提升。
2)clone_skb:限制內存的分配(clone_skb應該只是復制skb的結構體,不復制數據區)
此部分還沒有看懂,應該是跟cpu高速緩存相關,先放着,不懂並不影響后面的實驗。
3)延時:減小發送速率
在發送一個數據包后延時一會,延時的單位是ns級,從而達到減小發送速率的目的。若延時時間大於發送時間,應該是可以通過此功能達到每秒發送特定數據包個數的效果,即安特定的頻率發送數據包。
2.2搭建實驗環境
1)實驗拓撲如下
1 +-----------+ +-----------+ 2 | Host1 | | Host2 | 3 | eth1 +-----------+nf0 | 4 | | | | 5 | | | | 6 7 +-----------+ +-----------+
首先我們看下一個簡單代碼,對pktgen的shell 控制有個直觀感受,你可以先試着看看此代碼,也可以直接跳過,先看看下面的內容,然后再回過來看此代碼
#!/bin/sh # pktgen.conf -- Sample configuration for send on two devices on a UP system #modprobe pktgen if [[ `lsmod | grep pktgen` == "" ]];then modprobe pktgen fi if [[ $1 == "" ]];then pktsize=550 else pktsize=$1 fi function pgset() { local result echo $1 > $PGDEV result=`cat $PGDEV | fgrep "Result: OK:"` if [ "$result" = "" ]; then cat $PGDEV | fgrep Result: fi } function pg() { echo inject > $PGDEV cat $PGDEV } # On UP systems only one thread exists -- so just add devices # We use eth1, eth1 echo "Adding devices to run". PGDEV=/proc/net/pktgen/kpktgend_0 pgset "rem_device_all" pgset "add_device eth1" pgset "max_before_softirq 1" # Configure the individual devices echo "Configuring devices" PGDEV=/proc/net/pktgen/eth1 pgset "clone_skb 1000" pgset "pkt_size $pktsize" pgset "src_mac 00:1B:21:90:4B:E4" pgset "flag IPSRC_RND" pgset "src_min 10.0.0.2" pgset "src_max 10.0.0.255" pgset "dst 10.0.0.1" pgset "dst_mac 00:4E:46:31:30:00" pgset "count 0" # Time to run PGDEV=/proc/net/pktgen/pgctrl echo "pkgsize:$pktsize" echo "Running... ctrl^C to stop" pgset "start" echo "Done"
2)pktgen所有命令解釋如下
pktgen命令 |
|
Pktgen控制命令 |
|
start |
所有的線程開始發送 |
stop |
停止 |
線程的控制命令 |
|
add_device |
添加某個端口到某個線程 |
rem_device_all |
刪除綁定在某個線程的所有端口 |
max_before_softirq |
在最多發送多少個數據包后,執行do_softirq() |
端口命令 |
|
debug |
調試 |
clone_skb |
對每個skb進行多少個復制,0表示不復制。對於Dos等測試必須至零 |
clear_counters |
清空計數器,一般程序自動清空 |
pkt_size |
鏈路包的大小(前去CRC的值) |
min_pkt_size |
數據包最小值 |
max_pkt_size |
最大值 |
flags |
包的分片數量? |
count |
發送數據包的個數,0 表示一直發送 |
delay |
發送兩個數據包之間的延時 |
dst |
目的IP |
dst_min |
目的IP的最小值 |
dst_max |
最大值 |
src_min |
源IP最小值 |
src_max |
最大值 |
dst6 |
目的IPv6地址 |
src6 |
源IPv6地址 |
dstmac |
目的mac |
srcmac |
源mac |
src_mac_count |
源mac的數量,從srcmac設置的mac開始輪詢 |
dst_mac_count |
同上 |
udp_src_min |
最小源udp端口號 |
udp_src_max |
最大源udp端口號 |
udp_dst_min |
最小目的udp端口號 |
udp_dst_max |
最大目的udp端口號 |
flows |
並發流的個數 |
flowlen |
流的長度 |
Flags |
|
IPSRC_RND IPDST_RND TXSIZE_RND UDPSRC_RND UDPDST_RND MACSRC_RND MACDST_RND |
PSRC_RND 源IP隨機發送 |
3)配置實例
通過/proc接口配置pktgen,首先為了方便起見定義兩個配置函數
function pgset() { local result echo $1 > $PGDEV result=`cat $PGDEV | fgrep "Result: OK:"` if [ "$result" = "" ]; then cat $PGDEV | fgrep Result: fi } function pg() { echo inject > $PGDEV cat $PGDEV }
pktgen.conf-1 :在當CPU系統中將eth1 eth2 綁定到線程0,部分代碼如下
PGDEV=/proc/net/pktgen/kpktgend_0 pgset "rem_device_all" pgset "add_device eth1" pgset "add_device eth2"
pktgen.conf-2: eth1使用線程0 eth2使用線程1發送,部分代碼如下
PGDEV=/proc/net/pktgen/kpktgend_0 pgset "rem_device_all" pgset "add_device eth1" PGDEV=/proc/net/pktgen/kpktgend_1 pgset "rem_device_all" pgset "add_device eth2"
pktgen.conf-3:在雙cpu系統中 eth1 eth2都使用線程0發送,部分代碼如下
PGDEV=/proc/net/pktgen/kpktgend_0 pgset "rem_device_all" pgset "add_device eth1" pgset "add_device eth2" PGDEV=/proc/net/pktgen/kpktgend_1 pgset "rem_device_all"
pktgen.conf-4:用於Dos測試的腳本,注意clone_skb 0,部分代碼如下
PGDEV=/proc/net/pktgen/eth1 pgset "clone_skb 0" pgset "flag IPDST_RND" pgset "dst_min 10.0.0.0" pgset "dst_max 10.255.255.255"
pktgen.conf-5:用於路由流測試的腳本,同樣注意 clone_skb 0
PGDEV=/proc/net/pktgen/eth1 pgset "clone_skb 0" pgset "flag IPDST_RND" pgset "dst_min 10.0.0.0" pgset "dst_max 10.255.255.255" #8k concurrent flows at 4 pkts pgset "flows 8192" pgset "flowlen 4"
最后貼一個比較復雜的腳本:
#Script contributed by Grant Grundler # <grundler@parisc-linux.org> # Note! 10 devices PGDEV=/proc/net/pktgen/kpktgend_0 pgset "rem_device_all" pgset "add_device eth3" pgset "add_device eth5" pgset "add_device eth7" pgset "add_device eth9" pgset "add_device eth11" pgset "max_before_softirq 10000" PGDEV=/proc/net/pktgen/kpktgend_1 pgset "rem_device_all" pgset "add_device eth2" pgset "add_device eth4" pgset "add_device eth6" pgset "add_device eth8" pgset "add_device eth10" pgset "max_before_softirq 10000" # Configure the individual devices for i in 2 3 4 5 6 7 8 9 10 11 do PGDEV=/proc/net/pktgen/eth$i echo "Configuring $PGDEV" pgset "clone_skb 500000" pgset "min_pkt_size 60" pgset "max_pkt_size 60" pgset "dst 192.168.3.10$i" pgset "dst_mac 01:02:03:04:05:0$i" pgset "count 0" done echo "Running... CTRL-C to stop" PGDEV=/proc/net/pktgen/pgctrl pgset "start" tail -2 /proc/net/pktgen/eth*
相關鏈接:
Linux發包工具pktgen教程@蒼穹幻想