1. Packetdrill 編譯與安裝
/* Set the offload flags to be like a typical ethernet device */static void set_device_offload_flags(struct local_netdev *netdev){#ifdef linux// const u32 offload =// TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_TSO_ECN | TUN_F_UFO;// if (ioctl(netdev->tun_fd, TUNSETOFFLOAD, offload) != 0)// die_perror("TUNSETOFFLOAD");#endif}
./configure && make
使用方法
./packetdrill test.pkt
test.pkt為按Packetdrill語法編寫的測試腳本。
成功:無輸出,表示腳本正確,一切都符合預期。
失敗:指出腳本的錯誤地方,以及原因。
2. Packetdrill 執行自帶測試用例
// Test fast retransmit with 4 packets outstanding, receiver sending SACKs.// In this variant the receiver supports SACK.// Establish a connection.0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0 bind(3, ..., ...) = 0+0 listen(3, 1) = 0//三次握手+0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>+0 > S. 0:0(0) ack 1 <...>+.1 < . 1:1(0) ack 1 win 257+0 accept(3, ..., ...) = 4//系統調用,讓協議棧發出100個字節// Send 1 data segment and get an ACK, so cwnd is now 4.+0 write(4, ..., 1000) = 1000//預期協議棧會發出psh,ack,實際上發出了ack1//+0 > P. 1:1001(1000) ack 2//向協議棧注入 ack+.1 < . 1:1(0) ack 1001 win 257// Write 4 data segments.//系統調用,讓協議棧發出4000個字節+0 write(4, ..., 4000) = 4000//預期協議棧會發出psh,ack,實際上發出了seq 1001:2001, ack 1;seq 2001:3001, ack 1;seq 3001:4001, ack 1;[P.], seq 4001:5001, ack 1//+0 > P. 1001:5001(4000) ack 1// Get 3 SACKs.//向協議棧連續發出三個ack+.1 < . 1:1(0) ack 1001 win 257 <sack 2001:3001,nop,nop>+0 < . 1:1(0) ack 1001 win 257 <sack 2001:4001,nop,nop>+0 < . 1:1(0) ack 1001 win 257 <sack 2001:5001,nop,nop>// We've received 3 duplicate ACKs, so we do a fast retransmit.//預期協議棧會發出一次快速重傳 Seq 1001:2001,ack 1//+0 > . 1001:2001(1000) ack 1// Receiver ACKs all data.//向協議棧ack,響應所有報文的ack。+.1 < . 1:1(0) ack 6001 win 2574. 將fr-4pkt-sack-linux.pkt 中的修改如下。+0 > P. 1:1001(1000) ack 2 ? +0 > P. 1:1001(1000) ack 1//+0 > P. 1001:5001(4000) ack 1 ? +0 > . 1001:2001(1000) ack 1+0 > . 2001:3001(1000) ack 1+0 > . 3001:4001(1000) ack 1+0 > P. 4001:5001(1000) ack 1
[注解:如果執行packetdrill自帶的用例出錯,一般是協議棧發出的包沒有達到預期的包,先將預期>那部分干掉,然后再執行測試用例,然后通過抓包分析預期結果。通常是因為三次握手mss 的限制]
// 自己構造包實現三次重復的ack 1001.07:57:36.469280 IP 192.0.2.1.36840 > TENCENT64.site.webcache: Flags [.], ack 1001, win 257, options [sack 1 {2001:3001},nop,nop], length 007:57:36.469836 IP 192.0.2.1.36840 > TENCENT64.site.webcache: Flags [.], ack 1001, win 257, options [sack 1 {2001:4001},nop,nop], length 007:57:36.470349 IP 192.0.2.1.36840 > TENCENT64.site.webcache: Flags [.], ack 1001, win 257, options [sack 1 {2001:5001},nop,nop], length 0// 協議棧發起快速重傳。Seq 1001:2001,ack 1,100007:57:36.470376 IP TENCENT64.site.webcache > 192.0.2.1.36840: Flags [.], seq 1001:2001, ack 1, win 229, length 1000
3. Packetdrill 解讀自帶測試用例說明
這里主要說明packetdrill的基本語法。
腳本中可以包含四種語句:數據包、系統調用、shell命令、python語句。
每條語句都必須以時間戳開頭,指明它的執行時間。
數據包分為:輸入的數據包、輸出的數據包,格式類似于tcpdump的,
支持TCP、UDP、ICMP,以及TCP的大部分選項。
輸入數據包(<表示輸入):packetdrill會構造一個真實的數據包,然后注入協議棧。
例子:
0.100 < S 0:0(0) win 32792 <mss 1000, nop, nop, sackOK, nop, wscale 7>0.250 < [1:1461(1460)] icmp unreachable frag_needed mtu 1200
輸出數據包(>表示輸出):packetdrill會檢查協議棧是不是真的發出了這樣一個包。
+0 > udp (1472)
系統調用的格式類似于strace。
對于每個系統調用,packetdrill會在指定的時間給予執行,并檢查返回值是否和預期的一樣。系統調用的主要是應用于場景構造,已經非測試端的數據發送和接收。
常見的系統調用例子:
系統調用
connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) //客戶端連接服務器getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 //獲取scoketoptfcntl(3, F_SETFL, O_RDWR) = 0 //Fcntl設置ioctl(4, SIOCINQ, [1000]) = 0 //Ioctl設置read(3, ..., 1024) = 785 //讀取數據write(3, ..., 57) = 57 //寫入數據close(3) = 0 //關閉連接socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 //Tcp socketsetsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 //設置地址復用bind(3, ..., ...) = 0 //綁定端口listen(3, 1) = 0 //監聽端口accept(3, ..., ...) = 4 //接受連接
常見用法是用shell腳本設置內核參數或者調用shell命令統計tcp信息。設置
例子:
+0 `sysctl -q net.ipv4.tcp_timestamps=0`+0 `ss -4 -n state SYN-RECV | grep 192.168.0.1:8080 > /dev/null`
常見用法是使用python的assert斷言tcp_info的里面的信息,是否符合預期。
例子:
0.310 %{assert tcpi_reordering == 3assert tcpi_unacked == 10assert tcpi_sacked == 6assert tcpi_ca_state == TCP_CA_Recovery}%
每條語句都必須以時間戳開頭,指明它的執行時間,或者預期事件的發生時間。測試case有可能是timing的問題導致測試case無法通過。
時間戳可以使用多種格式:
Absolute(絕對時間):0.75Relative(相對時間):+0.2Wildcard(任意時間):*Range(絕對時間區間):0.750~0.900Relative Range(相對時間區間):+0.1~+0.2Loose(允許誤差值):--tolerance_usecs=800Blocking(阻塞時間區間):0.750...0.900
如果在規定的時間戳,對應的事件并沒有發生就會報錯,并告知該事件的實際發生時間。
+1.0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6>
預期在1s以后TCP應該發送一個SYNACK包。
在實際的使用中,一般指定–tolerance_usecs=405000,也就是允許4ms的時間誤差。
4. Packetdrill 實現基本場景構造測試
場景的場景構造是客戶端場景或者是服務器場景。具體包怎么構造,具體看packetdrill的自帶的測試用例。
1.服務端場景
構造服務器端場景:數據包輸入端是客戶端。數據包輸出端是系統調用,充當服務端。
// Establish a connection.0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 30.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 00.000 bind(3, ..., ...) = 00.000 listen(3, 1) = 00.000...0.200 accept(3, ..., ...) = 40.100 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>0.100 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 6>0.200 < . 1:1(0) ack 1 win 257//服務器端調用系統調用,預期發出2段數據包。0.300 write(4, ..., 2000) = 2000//0.300 > P. 1:2001(2000) ack 10.300 > . 1:1001(1000) ack 10.300 > P. 1001:2001(1000) ack 1
1.客戶端場景構造
構造服務器端場景:數據包輸入端是服務端。數據包輸出端是系統調用,充當客戶端。
// Create a socket and set it to non-blocking.0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 30.000 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)0.000 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0// Establish connection and verify that there was no error.0.100 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)0.100 > S 0:0(0) <mss 1460,sackOK,TS val 100 ecr 0,nop,wscale 6>0.200 < S. 0:0(0) ack 1 win 5792 <mss 1460,sackOK,TS val 700 ecr 100,nop,wscale 7>0.200 > . 1:1(0) ack 1 <nop,nop,TS val 200 ecr 700>//客戶端調用系統調用,預期發出http請求。// Send the HTTP request.0.200 write(3, ..., 57) = 570.200 > P. 1:58(57) ack 1 <nop,nop,TS val 200 ecr 700>0.300 < . 1:1(0) ack 58 win 92 <nop,nop,TS val 800 ecr 200>
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對VEVB武林網的支持。
新聞熱點
疑難解答
圖片精選