Packetdrill的简明使用手册

1. Packetdrill 编译与安装

  1. 源码链接 https://github.com/google/packetdrill.git
  2. 源码编译 注释netdev.c
/* 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 执行自带测试用例

  1. 开启tcpdump -i any tcp port 8080抓包便于分析
  2. 这里测试快速重传,测试环境centos7.2。
  3. 简单说明< 表示输入,packetdrill会构造一个真实的数据包。>表示预期协议栈会响应的数据包。(这个包不是由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 257
4. 将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 的限制]

  1. 执行: ../../../packetdrill fr-4pkt-sack-linux.pkt,无出错。
  2. 抓包可以看到一下结果:三次重复ack,则实施快速重传。达到预期效果。
// 自己构造包实现三次重复的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 0
07: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 0
07: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,1000
07: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语句。
每条语句都必须以时间戳开头,指明它的执行时间。

  • Packets

数据包分为:输入的数据包、输出的数据包,格式类似于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)
  • System Calls

系统调用的格式类似于strace。
对于每个系统调用,packetdrill会在指定的时间给予执行,并检查返回值是否和预期的一样。系统调用的主要是应用于场景构造,已经非测试端的数据发送和接收。

常见的系统调用例子:
系统调用

connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)  //客户端连接服务器
getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0  //获取scoketopt
fcntl(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 socket
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 //设置地址复用
bind(3, ..., ...) = 0  //绑定端口
listen(3, 1) = 0  //监听端口
accept(3, ..., ...) = 4 //接受连接
  • shell脚本用法

常见用法是用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脚本的用法

常见用法是使用python的assert断言tcp_info的里面的信息,是否符合预期。

例子:

0.310 %{
assert tcpi_reordering == 3
assert tcpi_unacked == 10
assert tcpi_sacked == 6
assert tcpi_ca_state == TCP_CA_Recovery
}%
  • 时间戳

每条语句都必须以时间戳开头,指明它的执行时间,或者预期事件的发生时间。测试case有可能是timing的问题导致测试case无法通过。

时间戳可以使用多种格式:

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的时间误差。

4. Packetdrill 实现基本场景构造测试

场景的场景构造是客户端场景或者是服务器场景。具体包怎么构造,具体看packetdrill的自带的测试用例。

1.服务端场景

构造服务器端场景:数据包输入端是客户端。数据包输出端是系统调用,充当服务端。

// Establish a connection.
0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
0.000 bind(3, ..., ...) = 0
0.000 listen(3, 1) = 0
0.000...0.200 accept(3, ..., ...) = 4
0.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 1
0.300 > . 1:1001(1000) ack 1
0.300 > P. 1001:2001(1000) ack 1

1.客户端场景构造

构造服务器端场景:数据包输入端是服务端。数据包输出端是系统调用,充当客户端。

// Create a socket and set it to non-blocking.
0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
0.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) = 57
0.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>

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • TCP协议详解_动力节点Java学院整理

    本文描述了TCP协议,首先简单介绍了TCP完成了一些什么功能:介绍了TCP报文格式,以及典型报文的数据格式:接着从链路控制和数据传输两个方面进行了介绍,在TCP中链路控制和数据传输是通过同一个通道进行的,并没有区分控制通道和数据通道:在网络中传输数据(控制或真实数据),网络可能发生拥堵,因此接下来简单描述了主机端进行拥塞控制所采取的方法,也简单提及了中间路由器/交换机进行拥塞避免所采取的主动措施:最后介绍了在TCP中性能分析的一些基本概念点,在开发网络应用程序的时候,需要对应用的网络需求进行一个

  • Java URL自定义私有网络协议

    --声明,脑残人士远离,本博客的核心不是if-else+前缀,而是如何通过URL协议处理框架定义私有协议 URI与URL的区别 URI (uniform resource identifier)统一资源标志符:URL(uniform resource location )统一资源定位符(或统一资源定位器):URI是一个相对来说更广泛的概念,URL是URI的一种,是URI命名机制的一个子集,可以说URI是抽象的,而具体要使用URL来定位资源.URI指向的一般不是物理资源路径,而是整个系统中的映射后

  • .Net WInform开发笔记(二)Winform程序运行结构图及TCP协议在Winform中的应用

    中午没事,把去年刚毕业那会画的几张图翻出来了,大概介绍Winform应用程序运行的过程,以及TCP协议在Winform中的应用.如果有Windows消息机制等基础,很好理解这两张图. (1)Winform应用程序运行结构图 (2)TCP通讯协议在Winform程序中的应用示意图 熟悉整个程序的来龙去脉,编程的时候就会很轻松,不会云里雾里. 另附公司招聘面试题一份,用了几次,发现效果不好,不知啥原因 1.简述接口.抽象类的区别. 2.简述重载(overload)与重写(override)的区别.

  • SQL Server 2008网络协议深入理解

    SQL Server 2008支持四种协议,Shared Memory:TCP/IP:Named Pipes和Virtual Interface Adapter(VIA).代开SQL Server配置管理器之后,会显示一个配置SQL Server服务,SQL Server网络协议和SQL Native Client协议的节点.可以通过展开SQL Server 2008网络配置节点进行服务器协议的配置. Shared Memory:Shared Meory协议只能由本地连接使用,因为它是一个用于服

  • python3实现TCP协议的简单服务器和客户端案例(分享)

    利用python3来实现TCP协议,和UDP类似.UDP应用于及时通信,而TCP协议用来传送文件.命令等操作,因为这些数据不允许丢失,否则会造成文件错误或命令混乱.下面代码就是模拟客户端通过命令行操作服务器.客户端输入命令,服务器执行并且返回结果. TCP(Transmission Control Protocol 传输控制协议):是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 793定义. TCP客户端 from socket import * host = '192

  • Getmac返回计算机中所有网卡的媒体访问控制 (MAC) 地址以及每个地址的网络协议列表

    返回计算机中所有网卡的媒体访问控制 (MAC) 地址以及每个地址的网络协议列表,既可以从本地方返回,也可以通过网络返回. 语法 getmac[.exe] [/s Computer [/u Domain\User [/p Password]]] [/fo {TABLE|LIST|CSV}] [/nh] [/v] 参数 /s Computer  指定远程计算机名称或 IP 地址(不能使用反斜杠).默认值是本地计算机.  /u Domain\User  运行具有由 user 或 domain\user

  • winsockfix网络协议修复工具

    如果由于病毒损坏了网络协议而无法上网,建议使用这个修复修复~~~本地下载

  • C#基于TCP协议的服务器端和客户端通信编程的基础教程

    运行在TCP之上常见的网络应用协议有比如HTTP.FTP.SMTP.POP3.IMAP. TCP是TCP/IP体系中最重要的传输协议,它提供全双工和可靠交付的服务,是大多数应用协议工作的基础. TCP是一种面向连接(连接导向)的,可靠的,基于字节流的传输层通信协议. TCP的工作过程 建立连接 传输数据 连接的终止 TCP的主要特点 1.TCP是面向连接的协议 2.是端到端的通信.每个TCP连接只能有两个端点,而且只能一对一通信,不能点对多的 的直接通信 3.高可靠性 4.全双工方式传输 5.数

  • Android编程使用HTTP协议与TCP协议实现上传文件的方法

    本文实例讲述了Android编程使用HTTP协议与TCP协议实现上传文件的方法.分享给大家供大家参考,具体如下: Android上传文件有两种方式,第一种是基于Http协议的HttpURLConnection,第二种是基于TCP协议的Socket. 这两种方式的区别是使用HttpURLConnection上传时内部有缓存机制,如果上传较大文件会导致内存溢出.如果用TCP协议Socket方式上传就会解决这种弊端. HTTP协议HttpURLConnection 1. 通过URL封装路径打开一个Ht

  • Java基于Tcp协议的socket编程实例

    本文实例讲述了Java基于Tcp协议的socket编程方法,分享给大家供大家参考.具体分析如下: 以下是一对一的通信编程实现,后续会继续学习一个服务器监听多个客户端的实现. 这里用到的主要步骤如下: 第一步:以特定端口(如4800)新建socket对象 第二步:以系统输入设备构造BufferedReader对象,该对象用于接收系统键盘输入的字符 第三步:以socket对象 得到输出流来构造PrintWriter 第四步:以socket对象得到输入流来构造相应的BufferedReader对象,该

  • 使用C语言编写基于TCP协议的Socket通讯程序实例分享

    tcp客户端示例 #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <stdio.h> #include <unistd.h>

随机推荐