Scapy DPDK extension is a testpmd forwarding engine and a set of command: tx, rx and expect(tx,rx,compare) packet, useful for development, unit test and fast regression.
- In case of multiple cores, each core share part of work, and it easy to reach 100G 64B line rate TX.
- Instead of traditional rx->tx forwarding, "expect" command introduced tx->rx to inspect returned packet with size, mbuf heads and whole packet hex check.
This document introduces basic syntax with examples.
- Scapy usage: http://scapy.readthedocs.io/en/latest/usage.html
- Remember to install python-libs and scapy using yum or apt
Enable python lib in dpdk configuration, build:
CONFIG_RTE_LIBRTE_PYTHON=y CONFIG_RTE_LIBRTE_PYTHON_VERSION=python2.7
- Start testpmd in interactive mode
# Continuously send simple packet
testpmd> tx 0 1
# Send scapy syntax packet
testpmd> tx 0 Ether()/IP()/UDP()/"hello"
# Flush a subnet
testpmd> tx 0 Ether()/IP(dst="192.168.0.1/24")
8776640/0 packets sent in 2167534.739us 4.049135mpps
# only send 1
testpmd> tx 0 Ether()/IP()/"hello" 1 0
1/1 packets sent in 1091.912us 0.000916mpps
# with simple scapy brief
testpmd> tx 0 Ether()/IP()/"hello" 1 0x01
Ether / 127.0.0.1 > 127.0.0.1 ip / Raw / Padding
1/1 packets sent in 1084.420us 0.000922mpps
# enum
testpmd> tx 0 Ether()/IP()/UDP(sport=[54321,54323]) 2 1
Ether / IP / UDP 127.0.0.1:54321 > 127.0.0.1:domain / Padding
Ether / IP / UDP 127.0.0.1:54323 > 127.0.0.1:domain / Padding
# range
testpmd> tx 0 Ether()/IP()/UDP(sport=(54321,54323)) 3 1
Ether / IP / UDP 127.0.0.1:54321 > 127.0.0.1:domain / Padding
Ether / IP / UDP 127.0.0.1:54322 > 127.0.0.1:domain / Padding
Ether / IP / UDP 127.0.0.1:54323 > 127.0.0.1:domain / Padding
# generate flows
testpmd> tx 0 Ether()/IP(dst="10.0.0.1/31")/TCP(dport=(55555,55556)) 4 2
<Ether dst=00:00:5e:00:01:19 src=80:18:44:e2:6e:fc type=IPv4 |<IP ihl=5L len=40 frag=0 proto=tcp chksum=0x990f src=10.12.205.180 dst=10.0.0.0 |<TCP dport=55555 dataofs=5L chksum=0xd50a |<Padding load='\x00\x00\x00\x00\x00\x00' |>>>>
<Ether dst=00:00:5e:00:01:19 src=80:18:44:e2:6e:fc type=IPv4 |<IP ihl=5L len=40 frag=0 proto=tcp chksum=0x990f src=10.12.205.180 dst=10.0.0.0 |<TCP dport=55556 dataofs=5L chksum=0xd509 |<Padding load='\x00\x00\x00\x00\x00\x00' |>>>>
<Ether dst=00:00:5e:00:01:19 src=80:18:44:e2:6e:fc type=IPv4 |<IP ihl=5L len=40 frag=0 proto=tcp chksum=0x990e src=10.12.205.180 dst=10.0.0.1 |<TCP dport=55555 dataofs=5L chksum=0xd509 |<Padding load='\x00\x00\x00\x00\x00\x00' |>>>>
<Ether dst=00:00:5e:00:01:19 src=80:18:44:e2:6e:fc type=IPv4 |<IP ihl=5L len=40 frag=0 proto=tcp chksum=0x990e src=10.12.205.180 dst=10.0.0.1 |<TCP dport=55556 dataofs=5L chksum=0xd508 |<Padding load='\x00\x00\x00\x00\x00\x00' |>>>>
4/4 packets sent in 2923.823us 0.001368mpps
# endless send until ctrl+c
testpmd> tx 0 Ether()/IP()/"hello" -1 0
1234567/-1 packets sent in 1091.912us 0.000916mpps
# continuously receive on port 0 until Ctrl+C
testpmd> rx 0
6721984/0 packets received in 1163983.125us 5.774984mpps
# Receive 1 packet from port 0 with simple dump
testpmd> rx 0 1 0 1
Ether / IP / UDP 127.0.0.1:domain > 127.0.0.1:domain / Padding
1/1 packets received in 2064638.250us 0.000000mpps
# receive 1 packet with mbuf header, brief and hex dump
testpmd> rx 0 1 10 0x32
RX P:0 Q:0 len:60 ptype:0x291 ol_flags:0x180 rss:0x00000000 fdir:0x0
ptype: L2_ETHER L3_IPV4_EXT_UNKNOWN L4_UDP
ol_flags: PKT_RX_L4_CKSUM_GOOD PKT_RX_IP_CKSUM_GOOD
<Ether dst=ff:ff:ff:ff:ff:ff src=00:00:00:00:00:00 type=IPv4 |<IP ihl=5L len=28 frag=0 proto=udp chksum=0x7cce src=127.0.0.1 dst=127.0.0.1 |<UDP len=8 chksum=0x172 |<Padding load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>>>
0000 FF FF FF FF FF FF 00 00 00 00 00 00 08 00 45 00 ..............E.
0010 00 1C 00 01 00 00 40 11 7C CE 7F 00 00 01 7F 00 ......@.|.......
0020 00 01 00 35 00 35 00 08 01 72 00 00 00 00 00 00 ...5.5...r......
0030 00 00 00 00 00 00 00 00 00 00 00 00 ............
1/1 packets received in 5180381.000us 0.000000mpps
Need one of following topo to get packet back:
- VF to VF
- use testpmd io forwarding on remote server of a back-to-back connection
- set NIC phy in loopback mode
- use loopback connector on NIC port
- physical connect two port that DPDK support
Default timeout: 10ms
# basic send
testpmd> expect 0 0 Ether()
tx: 1/1 1.211us 0.825826mpps rx: 1/1 7.571us 0.132077mpps round: 1/1 7.571us total: 7.571us 0.132077mpps
# if not recevied:
testpmd> expect 0 0 Ether()
Failed tx: 1/1 8.439us 0.118503mpps rx: 0/1 10006.879us 0.000000mpps round: 1/1 10006.879us total: 10006.879us 0.000000mpps
# if packet corrupted, auto diff hex:
testpmd> expect 0 0 Ether()/IP()
Failed: packet not same:
0000 FF FF FF FF FF FF 00 00 00 00 00 00 08 00 45 00 ..............E.
0000 00 00 00 00 00 00 FF FF FF FF FF FF 08 00 45 00 ..............E.
0010 0010 00 14 00 01 00 00 40 00 7C E7 7F 00 00 01 7F 00 ......@.|.......
0020 0020 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0030 0030 00 00 00 00 00 00 00 00 00 00 00 00 ............
RX P:0 Q:0 len:60 ptype:0x691 ol_flags:0x80 rss:0x00000000 fdir:0x0
ptype: L2_ETHER L3_IPV4_EXT_UNKNOWN L4_NONFRAG
ol_flags: PKT_RX_L4_CKSUM_UNKNOWN PKT_RX_IP_CKSUM_GOOD
tx: 1/1 1.494us 0.669507mpps rx: 1/1 6800.465us 0.000147mpps round: 1/1 6800.465us total: 6800.465us 0.000147mpps
# dump rx header info and assert hw offload flag filed
testpmd> expect 0 0 Ether()/IP()/UDP() 1 1 1 0x10 ol_flags 0x182
RX P:0 Q:1 len:60 ptype:0x291 ol_flags:0x182 rss:0xf2279e9d fdir:0x0 ptype: L2_ETHER L3_IPV4_EXT_UNKNOWN L4_UDP
ol_flags: PKT_RX_RSS_HASH PKT_RX_L4_CKSUM_GOOD PKT_RX_IP_CKSUM_GOOD
tx: 1/1 6.240us 0.160256mpps rx: 1/1 500.597us 0.001998mpps round: 1/1 500.597us total: 500.597us 0.001998mpps
Supported field check:
queue, ptype, rss, fdir, ol_flags, non|0
# no packet expect to be received:
testpmd> expect 0 0 Ether()/IP()/UDP() 0 1 100 0x10 0 0
tx: 1/1 9.058us 0.110397mpps rx: 0/0 100041.414us 0.000000mpps round: 1/1 100041.414us total: 100041.414us 0.000000mpps
# Fail and auto dump if we do receive one:
testpmd> expect 0 0 Ether()/IP()/UDP() 0 1 100 0x0 ol_flags 0x182
RX P:0 Q:1 len:60 ptype:0x291 ol_flags:0x182 rss:0xf2279e9d fdir:0x0
ptype: L2_ETHER L3_IPV4_EXT_UNKNOWN L4_UDP
ol_flags: PKT_RX_RSS_HASH PKT_RX_L4_CKSUM_GOOD PKT_RX_IP_CKSUM_GOOD
Failed tx: 1/1 5.353us 0.186805mpps rx: 1/0 100036.852us 0.000010mpps round: 1/1 100036.852us total: 100036.852us 0.000010mpps
# latency test, tx/rx 10000 rounds
testpmd> expect 0 0 Ether() 1 10000 1000 0 0 0
tx: 10000/10000 50401.309us 0.198408mpps rx: 10000/10000 50406.070us 0.198389mpps round: 10000/10000 5.041us total: 50406.070us 0.198389mpps
# tx and rx for 100ms - performance test
testpmd> expect 0 1 Ether() -1 1 100 0 0 0
tx: 114048/0 10003.931us 11.400319mpps rx: 108894/0 9985.172us 10.905571mpps round: 1/1 10003.931us total: 10003.931us 10.885121mpps
<timeout>:
- 0: endless loop, could be canceled by Ctrl+C
- integer: seconds(rx) or msecs(expect)
<verbose>: same to global verbose definition
- set verbose <level>
xxxx xxxx xxxx xxxx
= == ==== === ====
| || | ||| L-- RX 0:mute 1:short 2:brief 3:detail
| || | ||L----- RX header dump
| || | |L------ RX hex dump
| || | L------- Mute succeed expect command, for batch running
| || L------------ TX 0:mute 1:short 2:brief 3:detail
| |L--------------- TX header dump
| L---------------- TX hex dump
L------------------ Echo CLI to screen during "load" command
Any python grammar allowed:
testpmd> py 1+1
2
testpmd> py hex(12345)
'0x3039'
testpmd> py 0x12345
74565
testpmd> py a=Ether();b=UDP();a/IP()/b; a/IPv6()/b
<Ether type=IPv4 |<IP frag=0 proto=udp |<UDP |>>>
<Ether type=IPv6 |<IPv6 nh=UDP |<UDP |>>>
testpmd> py shell
>>> Help(Ether)
# "ctrl + d" to quit
Toggle python lib debug
A new engine to tx, rx and compare packets based on templates.
Behavior of idle:
- 0 - drop: rx only
- 1 - loopback: rx and send back
- 2 - forward: using testpmd port-queue mapping
- 3 - switch: switch mac address and send back
load and run testpmd CLI batch in mute
testpmd> load test/expect/init.exp
Change verbose level from 0 to 64
Read CLI commands from test/expect/init.exp
# verify
testpmd>py eth
<Ether dst=aa:bb:cc:dd:ee:ff src=00:11:22:33:44:55 |>
Set testpmd batch file loading with CLI echo to screen, easy to find source CLI if any error occurs.
testpmd> set verbose 0x8000
testpmd> load test/expect/rx.exp
testpmd> py eth = Ether(src="00:11:22:33:44:55",dst="aa:bb:cc:dd:ee:ff")
testpmd> py ethb = Ether(src="00:11:22:33:44:55",dst="ff:ff:ff:ff:ff:ff")
...
- Code format
- TX offload
- Jumbo packet send
- LRO rx
- Dynamic packet template - slow but flexible
- Test suit with summary
- mbuf packet type in scapy?
- dpdk wrapper for python - due to complexity to expand testpmd CLI, how about manipulating DPDK in python unit test framework?
- Syntax flexibility from Scapy
- Speed of DPDK
- Quick batch regression for developer to avoid anything broken