Sendip
是一个Linux
平台的命令行网络发包工具,目前支持的协议有IPv4、TCP、BGP、ICMP、UDP、RIP、NTP、IPv6、ICMPv6、RIPng
。Sendip
功能很强大,它支持自定义报文头部和数据(即任意的IP
数据包),连源IP
都可以随意写,而且里面也提供了一些默认的选项,可以按需构造数据包,非常方便。
作为一个简单的命令行工具,还支持从文件中直接读取整个packet
发送,所以很容易编写脚本批量测试。它只是个发包工具,对于发出去的包,收到了什么样的回复,Sendip
是不知道的,所以要得到回复的数据包就只能通过抓包工具了。它的源码也很简单,没有过多平台相关的代码,如果不理解也可以看源码。
一、Sendip安装
Sendip
的安装有两种方式,其一是直接通过源码包编译安装;其二是直接下载rpm
包或者通过命令行安装。
1、源码安装
Sendip
源码地址可通过github
直接下载,命令如下:git clone git@github.com:rickettm/SendIP.git
,下载后直接make; make install
编译安装后即可使用。
[root@localhost ~]# git clone git@github.com:rickettm/SendIP.git
Cloning into 'SendIP'...
remote: Enumerating objects: 246, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 246 (delta 0), reused 0 (delta 0), pack-reused 243
Receiving objects: 100% (246/246), 377.55 KiB | 230.00 KiB/s, done.
Resolving deltas: 100% (123/123), done.
[root@localhost SendIP]# ls
bgp.c compact.c csum.c dummy.h gnugetopt.c help2man icmp.h ipv4.h ipv6.h Makefile ntp.h rip.c ripng.c sendip.c sendip.spec.in tcp.h types.h udp.h
CHANGES contrib dummy.c gnugetopt1.c gnugetopt.h icmp.c ipv4.c ipv6.c LICENSE ntp.c README rip.h ripng.h sendip_module.h tcp.c TODO udp.c VERSION
[root@localhost SendIP]#
[root@localhost SendIP]# make
gcc -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -c -o csum.o csum.c
gcc -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -c -o compact.o compact.c
gcc -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -c -o sendip.o sendip.c
gcc -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -c -o gnugetopt.o gnugetopt.c
gcc -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -c -o gnugetopt1.o gnugetopt1.c
sh -c "if [ `uname` = Linux ] ; then
echo gcc -o sendip -g -rdynamic -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" sendip.o gnugetopt.o gnugetopt1.o compact.o ;
gcc -o sendip -g -rdynamic -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" sendip.o gnugetopt.o gnugetopt1.o compact.o -ldl -lm ;
elif [ `uname` = SunOS ] ; then
echo gcc -o sendip -g -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" sendip.o gnugetopt.o gnugetopt1.o compact.o ;
gcc -o sendip -g -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" sendip.o gnugetopt.o gnugetopt1.o compact.o -lsocket -lnsl -lm -ldl ;
else
echo gcc -o sendip -g -rdynamic -lm -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" sendip.o gnugetopt.o gnugetopt1.o compact.o ;
gcc -o sendip -g -rdynamic -lm -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" sendip.o gnugetopt.o gnugetopt1.o compact.o ;
fi"
gcc -o sendip -g -rdynamic -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS=/usr/local/lib/sendip sendip.o gnugetopt.o gnugetopt1.o compact.o
gcc -o ipv4.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -shared ipv4.c csum.o compact.o
gcc -o ipv6.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -shared ipv6.c csum.o compact.o
gcc -o icmp.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -shared icmp.c csum.o compact.o
gcc -o tcp.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -shared tcp.c csum.o compact.o
gcc -o udp.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -shared udp.c csum.o compact.o
gcc -o rip.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -shared rip.c csum.o compact.o
gcc -o ripng.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -shared ripng.c csum.o compact.o
gcc -o ntp.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -shared ntp.c csum.o compact.o
gcc -o bgp.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror -g -Wcast-align -DSENDIP_LIBS="/usr/local/lib/sendip" -shared bgp.c csum.o compact.o
./help2man -n "Send arbitrary IP packets" -N >sendip.1
echo -n '%define ver ' >sendip.spec
cat VERSION >>sendip.spec
cat sendip.spec.in >>sendip.spec
[root@localhost SendIP]# ls
bgp.c compact.c csum.c dummy.h gnugetopt.c help2man icmp.so ipv4.so ipv6.so ntp.c README ripng.c rip.so sendip.c sendip.spec tcp.h types.h udp.so
bgp.so compact.o csum.o gnugetopt1.c gnugetopt.h icmp.c ipv4.c ipv6.c LICENSE ntp.h rip.c ripng.h sendip sendip_module.h sendip.spec.in tcp.so udp.c VERSION
CHANGES contrib dummy.c gnugetopt1.o gnugetopt.o icmp.h ipv4.h ipv6.h Makefile ntp.so rip.h ripng.so sendip.1 sendip.o tcp.c TODO udp.h
[root@localhost SendIP]#
[root@localhost SendIP]# ./sendip -h
No hostname specified
Usage: ./sendip [-v] [-d data] [-h] [-f datafile] [-p module] [module options] hostname
-d data add this data as a string to the end of the packet
Data can be:
rN to generate N random(ish) data bytes;
0x or 0X followed by hex digits;
0 followed by octal digits;
any other stream of bytes
-s options set socket options
Valid options are:
b (SO_BROADCAST) allow sending packets to broadcast addresses;
i (IP_HDRINCL) (ON BY DEFAULT) include IP headers (expert use only!);
6 (IPV6_*) (ON BY DEFAULT) various options for setting ipv6 headers
-f datafile read packet data from file
-h print this message
-p module load the specified module (see below)
-v be verbose
Modules are loaded in the order the -p option appears. The headers from
each module are put immediately inside the headers from the previos model in
the final packet. For example, to embed bgp inside tcp inside ipv4, do
sendip -p ipv4 -p tcp -p bgp ....
Modules available at compile time:
ipv4 ipv6 icmp tcp udp bgp rip ntp
[root@localhost SendIP]# make install
[ -d /usr/local/lib/sendip ] || mkdir -p /usr/local/lib/sendip
[ -d /usr/local/bin ] || mkdir -p /usr/local/bin
[ -d /usr/local/share/man/man1 ] || mkdir -p /usr/local/share/man/man1
install -m 755 sendip /usr/local/bin
install -m 644 sendip.1 /usr/local/share/man/man1
install -m 755 ipv4.so ipv6.so icmp.so tcp.so udp.so rip.so ripng.so ntp.so bgp.so /usr/local/lib/sendip
#make install后,sendip即安装到Linux系统上,在任何位置可直接调用
[root@localhost ~]# sendip -h
No hostname specified
Usage: sendip [-v] [-d data] [-h] [-f datafile] [-p module] [module options] hostname
-d data add this data as a string to the end of the packet
Data can be:
rN to generate N random(ish) data bytes;
0x or 0X followed by hex digits;
0 followed by octal digits;
any other stream of bytes
-s options set socket options
Valid options are:
b (SO_BROADCAST) allow sending packets to broadcast addresses;
i (IP_HDRINCL) (ON BY DEFAULT) include IP headers (expert use only!);
6 (IPV6_*) (ON BY DEFAULT) various options for setting ipv6 headers
-f datafile read packet data from file
-h print this message
-p module load the specified module (see below)
-v be verbose
Modules are loaded in the order the -p option appears. The headers from
each module are put immediately inside the headers from the previos model in
the final packet. For example, to embed bgp inside tcp inside ipv4, do
sendip -p ipv4 -p tcp -p bgp ....
Modules available at compile time:
ipv4 ipv6 icmp tcp udp bgp rip ntp
2、下载RPM包或者命令行安装
在不同的平台下,安装方式有所区别,CentOS
平台无法直接通过命令行安装,Ubuntu
平台则可通过命令行直接安装。
1)CentOS平台:
在CentOS
平台下可以直接下载rpm
包,通过命令rpm -ivh
命令直接安装下载后的rpm
包;下载的地址如下:http://www.earth.li/projectpurple/progs/sendip.html
。可通过该地址下载rpm
包,当然也可通过该地址下载源码包。
[root@localhost tmp]# rpm -ivh sendip-2.5-1.i386.rpm
Verifying... ################################# [100%]
Preparing... ################################# [100%]
Updating / installing...
1:sendip-2.5-1 ################################# [100%]
[root@localhost tmp]# sendip -h
No hostname specified
Usage: sendip [-v] [-d data] [-h] [-f datafile] [-p module] [module options] hostname
-d data add this data as a string to the end of the packet
Data can be:
rN to generate N random(ish) data bytes;
0x or 0X followed by hex digits;
0 followed by octal digits;
any other stream of bytes
-f datafile read packet data from file
-h print this message
-p module load the specified module (see below)
-v be verbose
Modules are loaded in the order the -p option appears. The headers from
each module are put immediately inside the headers from the previos model in
the final packet. For example, to embed bgp inside tcp inside ipv4, do
sendip -p ipv4 -p tcp -p bgp ....
Modules available at compile time:
ipv4 ipv6 icmp tcp udp bgp rip ntp
2)Ubuntu平台:
在Ubuntu
平台下可通过命令行指令直接安装Sendip
工具,如下:
sudo apt-get update
sudo apt-get install sendip
二、Sendip用法
Sendip
用于发送任意IP
包,一般应用格式如下:
sendip [-v] [-l loopcount] [-t time] [-d data] [-h] [-f datafile] [-p module] [module options] hostname
-
通用选项:
-d 要携带的数据。rN随机产生N个字节,0x之后带十六进制,0之后带8进制。
-f 从文件中读取要携带的数据。
-p 加载协议模块,只有加载了才能使用。
-v 打印整个发出的包。
-
ipv4模块:
-iv x 版本 Default: 4
-ih x 首部长度 Default: Correct
-iy x 区分服务 Default: 0
-il x 总长度 Default: Correct
----------------------------------------------32bit
-ii x 标识 Default: Random
-ifr x 标志 Default: 0 (options are 0,1,r)
-if x 片偏移 Default: 0
----------------------------------------------32bit
-it x 生存时间 Default: 255
-ip x 协议 Default: 0, or set by underlying protocol
-ic x 首部检验和 Default: Correct
----------------------------------------------32bit
-is x 源地址 Default: 127.0.0.1
----------------------------------------------32bit
-id x 目的地址 Default: Correct
----------------------------------------------32bit
下面全是可选字段(比较少用,不译):
-ifd x IP don't fragment flag (see README)
Default: 0 (options are 0,1,r)
-ifm x IP more fragments flag (see README)
Default: 0 (options are 0,1,r)
-ionum x
IP option as string of hex bytes (length is always correct)
Default: (no options)
-ioeol IP option: end of list
-ionop IP option: no-op
-iorr x
IP option: record route. Format: pointer:addr1:addr2:...
-iots x
IP option: timestamp. Format: pointer:overflow:flag:(ip1:)ts1:(ip2:)ts2:...
-iolsr x
IP option: loose source route. Format: pointer:addr1:addr2:...
-iosid x
IP option: stream identifier
-iossr x
IP option: strict source route. Format: pointer:addr1:addr2:...
-
tcp模块:
-ts x 源端口 Default: 0
-td x 目的端口 Default: 0
----------------------------------------------32bit
-tn x 序号 Default: Random
----------------------------------------------32bit
-ta x 确认号 Default: 0
----------------------------------------------32bit
-tt x 数据偏移 Default: Correct
-tr x 保留(ECN、CWR看rfc2481) Default: 0
-tfu x URG Default: 0, or 1 if -tu specified (options are 0,1,r)
-tfa x ACK Default: 0, or 1 if -ta specified (options are 0,1,r)
-tfp x PSH Default: 0 (options are 0,1,r)
-tfr x RST Default: 0 (options are 0,1,r)
-tfs x SYN Default: 1 (options are 0,1,r)
-tff x FIN Default: 0 (options are 0,1,r)
-tw x 窗口 Default: 65535
----------------------------------------------32bit
-tc x 检验和 Default: Correct
-tu x 紧急指针 Default: 0
----------------------------------------------32bit
下面全是可选字段(比较少用,不译):
-tonum x TCP option as string of hex bytes (length is always correct)
Default: (no options)
-toeol TCP option: end of list
-tonop TCP option: no op
-tomss x
TCP option: maximum segment size
-towscale x
TCP option: window scale (rfc1323)
-tosackok
TCP option: allow selective ack (rfc2018)
-tosack x
TCP option: selective ack (rfc2018), format is l_edge1:r_edge1,l_edge2:r_edge2...
-tots x
TCP option: timestamp (rfc1323), format is tsval:tsecr
-
udp模块:
-us x 源端口 Default: 0
-ud x 目的端口 Default: 0
-ul x 长度 Default: Correct
-uc x 检验和 Default: Correct
注意:要按照从左到右的顺序依次封装报文,所以
ip
报文必须写在其他报文之前。如果协议中需要检验和之类的就按默认的就行了,省去计算的痛苦。
为进一步说明Sendip
的用法,我们通过两个例子来演示一下Sendip
的用法:
[root@localhost sendip]# sendip -p ipv4 -is 192.168.1.11 -id 192.168.1.12 -p udp -d r10 192.168.1.12 -v
Added 26 options
Initializing module ipv4
Initializing module udp
Finalizing module udp
Finalizing module ipv4
Final packet data:
45 00 00 26 E..&
7A 04 00 00 z...
FF 11 BE 5A ...Z
C0 A8 01 0B ....
C0 A8 01 0C ....
00 00 00 00 ....
00 12 16 98 ....
60 7B 94 46 `{.F
9C 8C 9A 9E ....
39 DD 9.
Sent 38 bytes to 192.168.1.12
Freeing module ipv4
Freeing module udp
#在目的主机通过tcpdump抓包查看
[root@localhost sendip]# tcpdump -i ens4f0v1 -n -c 10 -vvv
dropped privs to tcpdump
tcpdump: listening on ens4f0v1, link-type EN10MB (Ethernet), capture size 262144 bytes
16:02:28.528054 IP (tos 0x0, ttl 255, id 17349, offset 0, flags [none], proto UDP (17), length 38)
192.168.1.11.0 > 192.168.1.12.0: [udp sum ok] UDP, length 10
16:02:28.528109 IP (tos 0xc0, ttl 64, id 58036, offset 0, flags [none], proto ICMP (1), length 66)
192.168.1.12 > 192.168.1.11: ICMP 192.168.1.12 udp port 0 unreachable, length 46
IP (tos 0x0, ttl 255, id 17349, offset 0, flags [none], proto UDP (17), length 38)
192.168.1.11.0 > 192.168.1.12.0: [udp sum ok] UDP, length 10
16:02:33.682888 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.1.11 tell 192.168.1.12, length 28
16:02:33.682949 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.1.12 tell 192.168.1.11, length 28
16:02:33.682968 ARP, Ethernet (len 6), IPv4 (len 4), Reply 192.168.1.12 is-at 7e:6c:0c:13:80:a6, length 28
16:02:33.683035 ARP, Ethernet (len 6), IPv4 (len 4), Reply 192.168.1.11 is-at ea:0c:48:be:43:09, length 28
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel
[root@localhost sendip]# sendip -p ipv4 -is 192.168.1.11 -id 192.168.1.12 -p icmp -d 0x11ABCDEF 192.168.1.12 -v
Added 25 options
Initializing module ipv4
Initializing module icmp
Finalizing module icmp
Finalizing module ipv4
Final packet data:
45 00 00 1C E...
50 40 00 00 P@..
FF 01 E8 38 ...8
C0 A8 01 0B ....
C0 A8 01 0C ....
08 00 18 65 ...e
11 AB CD EF ....
Sent 28 bytes to 192.168.1.12
Freeing module ipv4
Freeing module icmp
#在目的主机通过tcpdump抓包查看
[root@localhost sendip]# tcpdump -i ens4f0v1 -n -c 10 -vvv
dropped privs to tcpdump
tcpdump: listening on ens4f0v1, link-type EN10MB (Ethernet), capture size 262144 bytes
16:00:24.577417 IP (tos 0x0, ttl 255, id 10025, offset 0, flags [none], proto ICMP (1), length 28)
192.168.1.11 > 192.168.1.12: ICMP echo request, id 4523, seq 52719, length 8
16:00:24.577454 IP (tos 0x0, ttl 64, id 30977, offset 0, flags [none], proto ICMP (1), length 28)
192.168.1.12 > 192.168.1.11: ICMP echo reply, id 4523, seq 52719, length 8
16:00:29.778785 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.1.11 tell 192.168.1.12, length 28
16:00:29.779764 ARP, Ethernet (len 6), IPv4 (len 4), Reply 192.168.1.11 is-at ea:0c:48:be:43:09, length 28
^C
4 packets captured
4 packets received by filter
0 packets dropped by kernel
其中主要的结构是sendip 网络层 上一层 数据 domain
,其中domain
是目的主机,如果出现什么错误就会打印出帮助信息,里面有一行是提示错误原因,别漏看了。至于能不能发不规则的包(如数据与报文长度不符合、校验和乱写之类的),实际会不会发出去就没进行测试了。
注意:
domain
字段可以和-id
的值不同,此时该数据包在主机发出后的第一个路由目标是domain
字段指示的地址,但该数据的的目的ip
地址为-id
的值。
三、Sendip实战
搭建测试实验环境,构造两个网络命名空间ns1
和ns2
模拟虚拟机,将智能网卡创建2
个VF
,将2
个VF
分别放到两个虚拟机中,即enp33s0f0v0
和enp33s0f0v1
,将VF代表口
分别绑定到ovs
的br-int
桥上,组网拓扑如下:
图1 逻辑拓扑
配置实验环境,执行如下脚本的命令:
#!/bin/bash
add_vm()
{
ip netns add ns1
ip netns add ns2
}
clean_vf()
{
echo 0 > /sys/class/net/enp33s0f0np0/device/sriov_numvfs
sleep 3
}
config_vf()
{
echo 2 > /sys/class/net/enp33s0f0np0/device/sriov_numvfs
sleep 2
}
setup_vf_to_ns()
{
ip link set enp33s0f0v0 netns ns1
ip link set enp33s0f0v1 netns ns2
ip netns exec ns1 ifconfig enp33s0f0v0 192.168.1.11/24 up
ip netns exec ns2 ifconfig enp33s0f0v1 192.168.1.12/24 up
sleep 5
ip netns exec ns1 ip a
ip netns exec ns2 ip a
}
add_vfr_to_br()
{
/usr/local/share/openvswitch/scripts/ovs-ctl start --system-id=random
sleep 3
ovs-vsctl add-br br-int
ovs-vsctl add-port br-int eth4
ovs-vsctl add-port br-int eth5
}
add_vm
clean_vf
config_vf
setup_vf_to_ns
add_vfr_to_br
其中,enp33s0f0v0
和enp33s0f0v1
是两个VF
,eth4
和eth5
为两个VF
的代表口。
这里以ovs offload
实验为例,说明通过sendip
发包工具构造多条流,配置ovs offload
功能,最终查看卸载流的结果。
[root@localhost script]# ovs-vsctl list open .
_uuid : 62206514-4201-47d1-8aa5-7ba5e0b8cdfd
bridges : [c70a822f-a896-4c75-bd4b-542e7afa72aa]
cur_cfg : 103
datapath_types : [netdev, system]
datapaths : {}
db_version : "8.3.1"
dpdk_initialized : false
dpdk_version : none
external_ids : {hostname=driver2-pc, rundir="/usr/local/var/run/openvswitch", system-id=""}
iface_types : [bareudp, erspan, geneve, gre, gtpu, internal, ip6erspan, ip6gre, lisp, patch, stt, system, tap, vxlan]
manager_options : []
next_cfg : 103
other_config : {hw-offload="true", tc-policy=none}
ovs_version : "3.1.0"
ssl : []
statistics : {}
system_type : unknown
system_version : unknown
根据hw-offload="true"
可知,当前ovs
支持offload
功能。
接下来通过crt_flow.sh
脚本生成流表文件flow_10000.txt
,该操作将以你想要生成的流表条数命名流表文件。crt_flow.sh
脚本使用格式:crt_flow.sh 流表条数 ovs入向代表口 ovs出向代表口
。
#!/bin/bash
#crt_flow.sh 1000 eth4 eth5
#eth4 and eth5 means the repr port in ovs
num=$1
p1=$2
p2=$3
ip_src=192.168.1.11
ip_dst=192.168.1.12
totalPort=$(expr $num + 2000)
rm -f ./flow_$num.txt
for((i=1025;i<$totalPort;i++))
do
echo in_port=$p1,nw_src=$ip_src,nw_dst=$ip_dst,dl_type=0x800,nw_proto=17,udp_dst=$i,actions=output:$p2 >> flow_$num.txt
#echo in_port=$p2,nw_src=$ip_dst,nw_dst=$ip_src,dl_type=0x800,nw_proto=17,udp_dst=$i,actions=output:$p1 >> flow_$num.txt
done
echo action=normal >> flow_$num.txt
通过crt_flow.sh
脚本生成openflow
流表,总计10001
条。
[root@localhost script]# ./crt_flow.sh 10000 eth4 eth5
[root@localhost script]#
[root@localhost script]# ls | grep flow_10000.txt
flow_10000.txt
[root@localhost script]# cat flow_10000.txt | tail -n 10
in_port=eth4,nw_src=192.168.1.11,nw_dst=192.168.1.12,dl_type=0x800,nw_proto=17,udp_dst=11016,actions=output:eth5
in_port=eth4,nw_src=192.168.1.11,nw_dst=192.168.1.12,dl_type=0x800,nw_proto=17,udp_dst=11017,actions=output:eth5
in_port=eth4,nw_src=192.168.1.11,nw_dst=192.168.1.12,dl_type=0x800,nw_proto=17,udp_dst=11018,actions=output:eth5
in_port=eth4,nw_src=192.168.1.11,nw_dst=192.168.1.12,dl_type=0x800,nw_proto=17,udp_dst=11019,actions=output:eth5
in_port=eth4,nw_src=192.168.1.11,nw_dst=192.168.1.12,dl_type=0x800,nw_proto=17,udp_dst=11020,actions=output:eth5
in_port=eth4,nw_src=192.168.1.11,nw_dst=192.168.1.12,dl_type=0x800,nw_proto=17,udp_dst=11021,actions=output:eth5
in_port=eth4,nw_src=192.168.1.11,nw_dst=192.168.1.12,dl_type=0x800,nw_proto=17,udp_dst=11022,actions=output:eth5
in_port=eth4,nw_src=192.168.1.11,nw_dst=192.168.1.12,dl_type=0x800,nw_proto=17,udp_dst=11023,actions=output:eth5
in_port=eth4,nw_src=192.168.1.11,nw_dst=192.168.1.12,dl_type=0x800,nw_proto=17,udp_dst=11024,actions=output:eth5
action=normal
#清除br-int上残存的旧的流表
[root@localhost script]# ovs-ofctl del-flows br-int
#添加flow_10000.txt文件内的流表到br-int
[root@localhost script]# ovs-ofctl add-flows br-int ./flow_10000.txt
#统计br-int上有多少条流表,实际是10001条,里面有一些非流表行和1条Normal流
[root@localhost script]# ovs-ofctl dump-flows br-int | wc -l
10016
#非流表行
[root@localhost script]# ovs-ofctl dump-flows br-int | grep NXST_FLOW
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4): flags=[more]
NXST_FLOW reply (xid=0x4):
# br-int上的Normal流
[root@localhost script]# ovs-ofctl dump-flows br-int | tail -n 1
cookie=0x0, duration=1135.442s, table=0, n_packets=104184, n_bytes=5759381, idle_age=0, actions=NORMAL
使用sendip
工具,构造发包脚本,发送10000
条流,这里主要通过改变每条流的发送和接收端口,从而构造10000
条流,这里需要进入到ns1
网络命名空间内运行脚本才行,脚本内容和操作如下:
[root@localhost script]# ip netns exec ns1 bash
[root@localhost script]# ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
21: enp33s0f0v0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 06:ba:b0:b9:79:82 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.11/24 brd 192.168.1.255 scope global enp33s0f0v0
valid_lft forever preferred_lft forever
inet6 fe80::4ba:b0ff:feb9:7982/64 scope link
valid_lft forever preferred_lft forever
[root@localhost script]# vi autosend.sh
[root@localhost script]# cat autosend.sh
#!/bin/bash
while true
do
for((i=1025;i<11025;i++))
do
sendip -p ipv4 -is 192.168.1.11 -id 192.168.1.12 -p udp -us $i -ud $i -f message 192.168.1.12
#sleep 0.1
done
done
[root@localhost script]# ./autosend.sh
其中,-f message
表示从文件message
中读取内容,message
中内容为Hello world!
。
查看ovs
上offload
了多少条流表,可通过如下命令进行查看:
[root@localhost ~]# ovs-appctl dpctl/dump-flows -m type=offloaded | wc -l
10001
[root@localhost ~]# ovs-appctl dpctl/dump-flows -m type=offloaded | head -n 10
ufid:e87373c0-45f9-472e-9657-c957817bd626, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth5),packet_type(ns=0/0,id=0/0),eth(src=32:94:88:3e:ca:95,dst=06:ba:b0:b9:79:82),eth_type(0x0800),ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=0/0,frag=no), packets:281, bytes:23323, used:0.620s, offloaded:yes, dp:tc, actions:eth4
ufid:8afa5a13-469b-43fe-9457-5204910958f5, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth4),packet_type(ns=0/0,id=0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.1.11,dst=192.168.1.12,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=0/0,dst=1025), packets:49, bytes:2695, used:3.250s, offloaded:yes, dp:tc, actions:eth5
ufid:6d3d008c-da89-40ec-8c12-3aaaee904056, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth4),packet_type(ns=0/0,id=0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.1.11,dst=192.168.1.12,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=0/0,dst=1026), packets:49, bytes:2695, used:3.250s, offloaded:yes, dp:tc, actions:eth5
ufid:bbacc902-f550-4294-a021-22294548f420, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth4),packet_type(ns=0/0,id=0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.1.11,dst=192.168.1.12,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=0/0,dst=1027), packets:49, bytes:2695, used:3.250s, offloaded:yes, dp:tc, actions:eth5
ufid:21ae5ef0-afd9-4a67-b53c-2b82c7577658, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth4),packet_type(ns=0/0,id=0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.1.11,dst=192.168.1.12,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=0/0,dst=1028), packets:49, bytes:2695, used:3.250s, offloaded:yes, dp:tc, actions:eth5
ufid:d3df18cd-b12a-4d8a-9567-243ee44001bc, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth4),packet_type(ns=0/0,id=0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.1.11,dst=192.168.1.12,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=0/0,dst=1029), packets:49, bytes:2695, used:3.250s, offloaded:yes, dp:tc, actions:eth5
ufid:d57add4c-8d40-43b1-931f-6cdecb6fbbcf, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth4),packet_type(ns=0/0,id=0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.1.11,dst=192.168.1.12,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=0/0,dst=1030), packets:49, bytes:2695, used:3.250s, offloaded:yes, dp:tc, actions:eth5
ufid:41e453f3-2495-4713-9899-6006d1b2a977, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth4),packet_type(ns=0/0,id=0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.1.11,dst=192.168.1.12,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=0/0,dst=1031), packets:49, bytes:2695, used:3.250s, offloaded:yes, dp:tc, actions:eth5
ufid:00c57cf3-3da4-4e63-b5f5-59fe16188422, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth4),packet_type(ns=0/0,id=0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.1.11,dst=192.168.1.12,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=0/0,dst=1032), packets:49, bytes:2695, used:3.250s, offloaded:yes, dp:tc, actions:eth5
ufid:0820c35c-5def-4a87-adc0-ab694b6a4bd1, skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(eth4),packet_type(ns=0/0,id=0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.1.11,dst=192.168.1.12,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=0/0,dst=1033), packets:49, bytes:2695, used:3.250s, offloaded:yes, dp:tc, actions:eth5
根据上面结果可知,ovs
总计offload
了10001
条流表,使用bwm-ng
统计PPS
和吞吐结果如下:
-
PPS
统计:
bwm-ng v0.6.2 (probing every 0.500s), press 'h' for help
input: /proc/net/dev type: rate
iface Rx Tx Total
==============================================================================
enp33s0f0v1: 1734.53 P/s 0.00 P/s 1734.53 P/s
------------------------------------------------------------------------------
total: 1734.53 P/s 0.00 P/s 1734.53 P/s
-
吞吐统计:
bwm-ng v0.6.2 (probing every 0.500s), press 'h' for help
input: /proc/net/dev type: rate
| iface Rx Tx Total
==============================================================================
enp33s0f0v1: 800.08 kb/s 0.00 b/s 800.08 kb/s
------------------------------------------------------------------------------
total: 800.08 kb/s 0.00 b/s 800.08 kb/s
根据上述结果,PPS
为每秒钟1700
多个包,吞吐为每秒0.78Mbit
,可见sendip
发包性能还是比较差的,如果要是测相关设备性能,则根本没法用,性能测试最好还是通过打流仪来做,如果没有打流仪,可以考虑使用pktgen
(参考Linux高性能网络测试工具 | pktgen)。如果做功能测试,则可以通过sendip
做发包工具进行测试。
另外,也可以通过tc
命令查看网卡是否offload
成功,如下:
[root@localhost ~]# tc -s -d filter show dev eth4 ingress
filter protocol ip pref 2 flower chain 0
filter protocol ip pref 2 flower chain 0 handle 0x1
eth_type ipv4
ip_proto udp
dst_ip 192.168.1.12
src_ip 192.168.1.11
dst_port 1025
ip_flags nofrag
in_hw in_hw_count 1
action order 1: mirred (Egress Redirect to device eth5) stolen
index 1 ref 1 bind 1 installed 3214 sec used 2 sec
Action statistics:
Sent 31295 bytes 569 pkt (dropped 0, overlimits 0 requeues 0)
Sent software 0 bytes 0 pkt
Sent hardware 31295 bytes 569 pkt
backlog 0b 0p requeues 0
cookie 135afa8afe439b4604525794f5580991
no_percpu
used_hw_stats delayed
filter protocol ip pref 2 flower chain 0 handle 0x2
eth_type ipv4
ip_proto udp
dst_ip 192.168.1.12
src_ip 192.168.1.11
dst_port 1026
ip_flags nofrag
in_hw in_hw_count 1
action order 1: mirred (Egress Redirect to device eth5) stolen
index 3 ref 1 bind 1 installed 3214 sec used 2 sec
Action statistics:
Sent 31295 bytes 569 pkt (dropped 0, overlimits 0 requeues 0)
Sent software 0 bytes 0 pkt
Sent hardware 31295 bytes 569 pkt
backlog 0b 0p requeues 0
cookie 8c003d6dec4089daaa3a128c564090ee
no_percpu
used_hw_stats delayed
......
Sent hardware
后面所接的报文数表示硬件offload
的报文数。在ns2
命名空间中,可以抓到数据包,如下:
[root@localhost script]# tcpdump -i enp33s0f0v1 -n -v -c 10
dropped privs to tcpdump
tcpdump: listening on enp33s0f0v1, link-type EN10MB (Ethernet), capture size 262144 bytes
15:12:09.436590 IP (tos 0x0, ttl 255, id 7069, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.stun > 192.168.1.12.stun: UDP, length 13
15:12:09.437334 IP (tos 0x0, ttl 255, id 64135, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.twrpc > 192.168.1.12.twrpc: UDP, length 13
15:12:09.438107 IP (tos 0x0, ttl 255, id 12078, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.plethora > 192.168.1.12.plethora: UDP, length 13
15:12:09.438841 IP (tos 0x0, ttl 255, id 11001, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.cleanerliverc > 192.168.1.12.cleanerliverc: UDP, length 13
15:12:09.439580 IP (tos 0x0, ttl 255, id 17527, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.vulture > 192.168.1.12.vulture: UDP, length 13
15:12:09.440360 IP (tos 0x0, ttl 255, id 30390, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.slim-devices > 192.168.1.12.slim-devices: UDP, length 13
15:12:09.441126 IP (tos 0x0, ttl 255, id 12246, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.gbs-stp > 192.168.1.12.gbs-stp: UDP, length 13
15:12:09.441828 IP (tos 0x0, ttl 255, id 27537, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.celatalk > 192.168.1.12.celatalk: UDP, length 13
15:12:09.442438 IP (tos 0x0, ttl 255, id 6423, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.ifsf-hb-port > 192.168.1.12.ifsf-hb-port: UDP, length 13
15:12:09.443383 IP (tos 0x0, ttl 255, id 51399, offset 0, flags [none], proto UDP (17), length 41)
192.168.1.11.ltcudp > 192.168.1.12.ltcudp: UDP, length 13
10 packets captured
12 packets received by filter
0 packets dropped by kernel
综合来看,在日常工作中测试多条流offload
时,可以使用sendip
来作为发包工具进行测试,毕竟打流仪太贵了,即使公司购买了打流仪,打流仪的使用往往也比较紧张,因为打流仪的口太少了,无法供太多人同时使用。
因此,某些测试场景下,我们可以使用sendip
作为发包工具。
原文始发于微信公众号(Linux二进制):Linux网络发包工具 | Sendip
暂无评论内容