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),用于注入协议栈。

完整例子如下:

// Establish a connection. 服务端socket函数调用
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 // 客户端的socket函数调用不用显式指出
// 客户端构造SYN包,注入协议栈
+0 < S 0:0(0) win 32792 <mss 1000, sackOK, nop, nop, nop, wscale 7> // 预期协议栈发送SYNACK包
+0 > S. 0:0(0) ack 1 <...> // 客户端构造ACK包,注入协议栈,完成三次握手
+.1 < . 1:1(0) ack 1 win 257 // 服务端接受连接
+0 accept(3, ..., ...) = 4 // Send 1 data segment and get an ACK,构造收发包场景
+0 write(4, ..., 1000) = 1000
+0 > P. 1:1001(1000) ack 1
+.1 < . 1:1(0) ack 1001 win 257
+0 %{ print tcpi_snd_cwnd }% // Write 4 data segments
+0 write(4, ..., 4000) = 4000
+0 > P. 1001:5001(4000) ack 1 // Get 3 SACKs,构造快速重传场景
+.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.
// 收到3个SACK后,预期协议栈会快速重传
+0 > . 10001:2001(1000) ack 1 // Receiver ACKs all data.
+.1 < . 1:1(0) ack 6001 win 257

实现

Packetdrill是一个用户态应用程序,主要用C语言编写。

使用flex构造词法分析器,使用bison构造语法分析器。

脚本解释器包括一个主线程和一个用于执行阻塞的系统调用的线程。

使用packet socket来验证输出的数据包,使用TUN device来注入输入的数据包。

具体代码可见项目。

测试案例

一些用于测试具体场景的测试案例:

fast_retransmit // 快速重传

early_retransmit // ER补丁测试

blocking // 阻塞的系统调用

fast_recovery // PRR补丁测试

initial_window // 初始cwnd

init_rto // SYNACK包的RTO

close

connect

icmp

inet_diag

ioctl

listen

mss

pmtu_discovery

receiver_rtt

sack

shutdown

undo

run_tests.h为一个测试脚本:

#!/bin/bash
for f in `find . -name "*.pkt" | sort`; do
echo "Running $f ..."
ip tcp_metrics flush all &> /dev/null
../../packetdrill $f
done

注意:Due to TCP metrics caching in recent kernels, a second run of all tests can result in failures.

The script run_tests.sh in this directory uses the iproute tool to flush the TCP metrics cache

before each test.

这些测试脚本在3.11.0-12-generic中都能通过。

偶尔有timing error,是正常现象,可用--tolerance_usecs=405000指定允许的时间误差。

我的体验

测试一个简单的场景:连接建立后,服务端发送10个包。

这时候处于慢启动阶段,cwnd是指数增长的。

按理来说每收到1个ACK,cwnd++;每收到1个delayed ACK,cwnd+=2。最终cwnd应该为20。

但测试结果表明,最终cwnd为12。

进一步分析发现这是受到拥塞窗口有效性验证机制的影响,当发送是受到应用程序的限制(没有新数据可供发送),

而不是受到cwnd的限制时,不允许增加cwnd。

当然,这只是一个小例子,说明Packetdrill有助于网络协议栈的分析。

优缺点

任何一个工具都有优点和限制,Packetdrill也不例外。

(1) 优点

属于脚本测试工具,能够快速和方便的测试网络协议栈,自由的构造测试场景。

因为是用脚本测试,所以快速方便,不用大动干戈。

可以在产品机上直接测试,因此测结果是真实的。

场景可重现,测试可自动执行。

比较通用,支持IPv4和IPv6,支持多种操作系统。

(2) 缺点

属于黑盒测试工具,虽然它能通过TCP_INFO选项从内核中获取一些信息,但是这些信息毕竟有限。

当预期结果不符时,缺少信息来做进一步判断。

编写测试脚本时,需要对要构造的场景十分了解,知道协议栈是如何具体处理的(对每一步了如指掌)。

所以,当场景比较复杂时(比如涉及到较多的数据包、往返时延),编写脚本的难度大大增加了。

另外目前只支持测试单条连接,不允许同时测试多条连接。

Reference

[1] packetdrill: Scriptable Network Stack Testing, from Sockets to Packets

[2] Drilling Network Stacks with packetdrill

[3] https://code.google.com/p/packetdrill/

不错的网络协议栈测试工具 — Packetdrill的更多相关文章

  1. 转载: 一、linux cpu、内存、IO、网络的测试工具

    来源地址: http://blog.csdn.net/wenwenxiong/article/details/77197997 记录一下 以后好找.. 一.linux cpu.内存.IO.网络的测试工 ...

  2. LINUX下一款不错的网站压力测试工具webbench

    LINUX下一款不错的网站压力测试工具webbench 分类: Linux 2014-07-03 09:10 220人阅读 评论(0) 收藏 举报 [html] view plaincopy wget ...

  3. 不错的网络协议栈測试工具 — Packetdrill

    Packetdrill - A network stack testing tool developed by Google. 项目:https://code.google.com/p/packetd ...

  4. 找到一款不错的网站压力测试工具webbench

    webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便. 1.适用系统:Linux 2.编译安装: 引用 wget htt ...

  5. 一款不错的网站压力测试工具webbench

    webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便. 1.适用系统:Linux 2.编译安装: 引用 wget htt ...

  6. 不错的网站压力测试工具webbench

    webbench最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便. 1.适用系统:Linux 2.前期准备:yum install ...

  7. 【转】LINUX下一款不错的网站压力测试工具webbench

    原文链接:http://blog.csdn.net/xinqingch/article/details/8618704 安装: wget http://blog.s135.com/soft/linux ...

  8. 15款免费WiFi入侵破解安全测试工具

    以下是的15款免费(接近免费)的WiFi网络入侵测试工具.这些工具将帮你发现流氓AP,弱Wi-Fi密码等安全隐患,在黑客光临之前把漏洞补上. 一.Vistumbler扫描器 Kismet是一个开源的W ...

  9. 转载:开发者眼中最好的 22 款 GUI 测试工具

    对于很多同学来说gui程序的测试是一个难点,所以我从网上转载了一篇关于gui测试的一篇文章,里面罗列的很多工具,大家可以尝试一下学习学习. 英文原文:22 best GUI testing tools ...

随机推荐

  1. EBS开发性能优化之查找需要优化的程序

    1.登陆数据库LINUX环境 使用 top 命令查看进程状况 [oratest@ebsdb~]$top top - 15:58:59 up 8 days, 22:04,  1 user,  load ...

  2. [Pelican]Pelican入门(二)

    之前是搭建了一个简单的博客,但是没有图片,没有具体的栏目分类 这次来研究下 一 导航栏 之前是直接把.md扔到的content文件夹下,结果导航栏,显示的是Category信息. 现在这么改成 D:. ...

  3. [error]configure: error: You need a C++ compiler for C++ support.

    安装pcre包的时候提示缺少c++编译器 解决办法 使用yum安装 yum -y install gcc-c++ 本文出自 "orangleliu笔记本"博客,转载请务必保留此出处 ...

  4. css模块化及CSS Modules使用详解

    什么是css模块化? 为了理解css模块化思想,我们首先了解下,什么是模块化,在百度百科上的解释是,在系统的结构中,模块是可组合.分解和更换的单元.模块化是一种处理复杂系统分解成为更好的可管理模块的方 ...

  5. quartz 时间设置(定时任务scheduler)

    quartz用来设置定时任务的作业调度程序.在linux的crontab中用到. 格式为: * * * * * * * 其从左到右顺序代表 :[秒] [分] [小时] [日] [月] [周] [年] ...

  6. Cocos2D iOS之旅:如何写一个敲地鼠游戏(一):高清屏显示和UIKit

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  7. 【Linux驱动】字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 1.字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面 ...

  8. Android:android sdk源码中怎么没有httpclient的源码了

    欢迎关注公众号,每天推送Android技术文章,二维码如下:(可扫描) 今天想使用这个API,怎么也找不到.废了好多时间... 查阅资料才知道如下解释: 在android 6.0(API 23)中,G ...

  9. 秒懂ASP.NET中的内置对象

    上篇博客,小编主要简单的介绍了一下ASP.NET中的控件,这篇博客,小编主要简单总结一下ASP.NET中的内置对象,七个内置对象分别是:Request.Response.Application.Coo ...

  10. iOS中 自定义cell升级版 (高级)

    接上次分享的自定义cell进行了优化:http://blog.csdn.net/qq_31810357/article/details/49611255 指定根视图: self.window.root ...