Packetdrill – A network stack testing tool developed by Google.
项目:https://code.google.com/p/packetdrill/
本文:zhangskd @ csdn blog
简介
The packetdrill scripting tool enables quick, precise tests for entire TCP/UDP/IPv4/IPv6 network stacks,
from the system call layer down to the NIC hardware.
截至2013年开源时,Packetdrill已经在Google内部使用了18个月,主要用于以下几个用途:
(1) Regression testing of network stack
"we have a suite of hundreds of packetdrill scripts that are run by all developers on our team before
submitting a patch for review."
对网络协议栈进行回归测试,确保新的功能不会影响网络协议栈的可用性。
总共包含657个test cases。
(2) Test-driven development of network protocols
"we have developed several new features for Linux TCP using packetdrill."
在以下几个TCP新特性的开发中发挥重要作用:
Early Retransmit
Fast Open
Loss Probes
Rewrite of F-RTO
(3) Reproduction of bugs seen in production network traces
"we have used packetdrill to isolate hard-to-reproduce bugs seen in complex real traces."
使用它发现了Linux内核的10个bug。
安装和使用
(1) 安装
首先安装flex和bison,用于构建词法和语法分析器。
然后编译即可:
cd packetdrill
./configure
make
(2) 使用
./packetdrill test.pkt
test.pkt为按Packetdrill语法编写的测试脚本。
成功:无输出,表示脚本正确,一切都符合预期。
失败:指出脚本的错误地方,以及原因。
语法
The tool supports four types of statements: packets, system calls, shell commands, and Python scripts.
Each statement is timestamped and is executed by the interpreter in real time, verifying that events
proceed as the script expects.
脚本中可以包含四种语句:数据包、系统调用、shell命令、python语句。
每条语句都必须以时间戳开头,指明它的执行时间。
(1) Packets
数据包分为:输入的数据包、输出的数据包,格式类似于tcpdump的,
支持TCP、UDP、ICMP,以及TCP的大部分选项。
输入的数据包(input packets)
对于输入的数据包(<表示输入),packetdrill会构造一个真实的数据包,然后注入协议栈。
< denotes an input packet to construct and inject into the system under test.
Here’s an example of a TCP SYN packet, which packetdrill creates and injects into the
network stack under test 100ms after the start of the test:
0.100 < S 0:0(0) win 32792 <mss 1000, nop, nop, sackOK, nop, wscale 6>
输出的数据包(outbound packets)
对于输出的数据包(>表示输出),packetdrill会检查协议栈是不是真的发出了这样一个包。
> denotes an output packet to sniff and verify, to expect the system to send.
Here’s an example of an outbound UDP packet expected to be sent immediately after
a prior event(denoted by +0), which packetdrill sniffs and then verifies for matching
specification:
+0 > udp (1472)
(2) System Calls
系统调用的格式类似于strace。
对于每个系统调用,packetdrill会在指定的时间给予执行,并检查返回值是否和预期的一样。
Here’s an example of a bind() system call invocation in packetdrill notation:
+0 bind(3, …, …) = 0
In this example, 3 denotes the file descriptor number to pass in, and the = 0 denotes the expected
return value (i.e.., the user expects the system call to succeed).
The ellipsis (…) allows scripts to omit irrelevant details.
(3) Shell Commands
允许在脚本中使用shell命令,用反引号括起来。
+0 `sysctl -q net.ipv4.tcp_timestamps=0`
(4) Python Commands
允许在脚本中使用Python命令,用%{和}%括起来。
Packetdrill allows inline Python code snippets to print information and to make assertions about the
internal state of a TCP socket using the TCP_INFO getsockopt() option.
The following Linux-based example asserts that the sender’s congestion window is 10 packets:
+0 %{ assert tcpi_snd_cwnd == 10 }%
(5) 时间戳
每条语句都必须以时间戳开头,指明它的执行时间,或者预期事件的发生时间。
时间戳可以使用多种格式:
Absolute(绝对时间):0.75
Relative(相对时间):+0.2
Wildcard(任意时间):*
Range(绝对时间区间):0.750~0.900
Relative Range(相对时间区间):+0.1~+0.2
Loose(允许误差值):–tolerance_usecs=800
Blocking(阻塞时间区间):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的时间误差。
(6) 完整例子
验证TCP的快速重传功能,fast retransmit说白了就是收到3个重复的ACK或SACK后马上重传一个数据包
(对于FACK来说只要孔>=3个包即可)。
脚本中服务器端的协议栈是要观测的对象,对应的是输出的数据包(outbound packet)。
脚本中客户端对应的是输入的数据包(inbound packet),用于注入协议栈。
而只有在充满了艰辛的人生旅途中,始终调整好自己观风景的心态,