diff options
author | Yong Liu <yong.liu@intel.com> | 2014-09-10 13:25:52 +0800 |
---|---|---|
committer | Yong Liu <yong.liu@intel.com> | 2014-09-10 13:25:52 +0800 |
commit | ddbe46a51d4d5352737a1077b25cfe283a4d1fb2 (patch) | |
tree | 99d53ffb5bb5c1aba8c8b4fda39a9eece3763a0b /tests |
import dcts first version
Diffstat (limited to 'tests')
-rw-r--r-- | tests/TestSuite_blacklist.py | 125 | ||||
-rw-r--r-- | tests/TestSuite_checksum_offload.py | 317 | ||||
-rw-r--r-- | tests/TestSuite_cmdline.py | 124 | ||||
-rw-r--r-- | tests/TestSuite_fdir.py | 335 | ||||
-rw-r--r-- | tests/TestSuite_hello_world.py | 86 | ||||
-rw-r--r-- | tests/TestSuite_ieee1588.py | 145 | ||||
-rw-r--r-- | tests/TestSuite_ip_pipeline.py | 567 | ||||
-rw-r--r-- | tests/TestSuite_ipfrag.py | 381 | ||||
-rw-r--r-- | tests/TestSuite_jumboframes.py | 226 | ||||
-rw-r--r-- | tests/TestSuite_l2fwd.py | 215 | ||||
-rw-r--r-- | tests/TestSuite_l3fwd.py | 602 | ||||
-rw-r--r-- | tests/TestSuite_link_flowctrl.py | 407 | ||||
-rw-r--r-- | tests/TestSuite_multiprocess.py | 258 | ||||
-rw-r--r-- | tests/TestSuite_pmd.py | 477 | ||||
-rw-r--r-- | tests/TestSuite_pmd_bonded.py | 1098 | ||||
-rw-r--r-- | tests/TestSuite_timer.py | 86 | ||||
-rw-r--r-- | tests/TestSuite_vlan.py | 182 | ||||
-rw-r--r-- | tests/TestSuite_whitelist.py | 197 |
18 files changed, 5828 insertions, 0 deletions
diff --git a/tests/TestSuite_blacklist.py b/tests/TestSuite_blacklist.py new file mode 100644 index 0000000..a7e5ca3 --- /dev/null +++ b/tests/TestSuite_blacklist.py @@ -0,0 +1,125 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test device blacklisting. + +""" + +import dcts + + +from test_case import TestCase + + +# +# +# Test class. +# +class TestBlacklist(TestCase): + + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + Run at the start of each test suite. + + Blacklist Prerequisites. + Requirements: + Two Ports + """ + + self.ports = self.dut.get_ports(self.nic) + self.verify(len(self.ports) >= 2, "Insufficient ports for testing") + self.regexp_blacklisted_port = "EAL: PCI device 0000:%s on NUMA socket [-0-9]+[^\n]*\nEAL: probe driver[^\n]*\nEAL: Device is blacklisted, not initializing" + + def set_up(self): + """ + Run before each test case. + Nothing to do. + """ + pass + + def check_blacklisted_ports(self, output, ports, blacklisted=False): + """ + Check if any of the ports in `ports` have been blacklisted, if so, raise + exception. + If `blacklisted` is True, then raise an exception if any of the ports + in `ports` have not been blacklisted. + """ + for port in ports: + + # Look for the PCI ID of each card followed by + # "Device is blacklisted, not initializing" but avoid to consume more + # than one device. + regexp_blacklisted_port = self.regexp_blacklisted_port % self.dut.ports_info[port]['pci'] + + matching_ports = dcts.regexp(output, regexp_blacklisted_port, True) + + if blacklisted: + self.verify(len(matching_ports) == 1, + "Blacklisted port is being initialized") + else: + self.verify(len(matching_ports) == 0, + "Not blacklisted port is being blacklisted") + + def test_bl_noblacklisted(self): + """ + Run testpmd with no blacklisted device. + """ + + cmdline = r"./%s/build/app/test-pmd/testpmd -n 1 -c 3 -- -i" % self.target + out = self.dut.send_expect(cmdline, "testpmd> ", 120) + rexp = r"Link" + match_status = dcts.regexp(out, rexp, True) + + self.check_blacklisted_ports(out, self.ports) + + def test_bl_oneportblacklisted(self): + """ + Run testpmd with one port blacklisted. + """ + self.dut.kill_all() + + cmdline = r"./%s/build/app/test-pmd/testpmd -n 1 -c 3 -b 0000:%s -- -i" % (self.target, self.dut.ports_info[0]['pci']) + out = self.dut.send_expect(cmdline, "testpmd> ", 120) + + self.check_blacklisted_ports(out, self.ports[1:]) + + def test_bl_allbutoneportblacklisted(self): + """ + Run testpmd with all but one port blacklisted. + """ + self.dut.kill_all() + + ports_to_blacklist = self.ports[:-1] + + cmdline = "./%s/build/app/test-pmd/testpmd -n 1 -c 3" % self.target + for port in ports_to_blacklist: + cmdline += " -b 0000:%s" % self.dut.ports_info[port]['pci'] + + cmdline += " -- -i" + out = self.dut.send_expect(cmdline, "testpmd> ", 180) + + blacklisted_ports = self.check_blacklisted_ports(out, + ports_to_blacklist, + True) + + def tear_down(self): + """ + Run after each test case. + Quit testpmd. + """ + self.dut.send_expect("quit", "# ", 10) + + def tear_down_all(self): + """ + Run after each test suite. + Nothing to do. + """ + pass diff --git a/tests/TestSuite_checksum_offload.py b/tests/TestSuite_checksum_offload.py new file mode 100644 index 0000000..e80c26a --- /dev/null +++ b/tests/TestSuite_checksum_offload.py @@ -0,0 +1,317 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test support of RX/TX Checksum Offload Features by Poll Mode Drivers. + +""" + +import dcts +import string +import re +import rst + +from test_case import TestCase + +# +# +# Test class. +# + + +class TestChecksumOffload(TestCase): + + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + Run at the start of each test suite. + + Checksum offload prerequisites. + """ + # Based on h/w type, choose how many ports to use + self.dut_ports = self.dut.get_ports_performance(self.nic) + + # Verify that enough ports are available + self.verify(len(self.dut_ports) >= 2, "Insufficient ports for testing") + + # Verify that enough threads are available + cores = self.dut.get_core_list("1S/2C/2T") + self.verify(cores is not None, "Insufficient cores for speed testing") + + self.coreMask = dcts.create_mask(cores) + self.portMask = dcts.create_mask([self.dut_ports[0], self.dut_ports[1]]) + self.ports_socket = self.dut.get_numa_id(self.dut_ports[0]) + + def set_up(self): + """ + Run before each test case. + """ + if self.dut.want_func_tests: + self.dut.send_expect("./%s/build/app/test-pmd/testpmd -c %s -n 1 -- -i --burst=1 --txpt=32 --txht=8 --txwt=0 --txfreet=0 --rxfreet=64 --mbcache=250 --portmask=%s --disable-hw-vlan --enable-rx-cksum --crc-strip" % (self.target, self.coreMask, self.portMask), "testpmd>", 120) + self.dut.send_expect("set verbose 1", "testpmd>") + self.dut.send_expect("set fwd csum", "testpmd>") + + def checksum_validate(self, packets_sent, packets_expected): + """ + Validate the checksum. + """ + tx_interface = self.tester.get_interface(self.tester.get_local_port(self.dut_ports[1])) + rx_interface = self.tester.get_interface(self.tester.get_local_port(self.dut_ports[0])) + + checksum_pattern = re.compile("chksum.*=.*(0x[0-9a-z]+)") + + chksum = dict() + result = dict() + + self.tester.send_expect("scapy", ">>> ") + self.tester.send_expect('sys.path.append("./")', ">>> ") + self.tester.send_expect('from sctp import *', ">>> ") + + for packet_type in packets_expected.keys(): + self.tester.send_expect("p = %s" % packets_expected[packet_type], ">>>") + out = self.tester.send_expect("p.show2()", ">>>") + chksums = checksum_pattern.findall(out) + chksum[packet_type] = chksums + + self.tester.send_expect("exit()", "#") + + self.tester.scapy_background() + self.tester.scapy_append('sys.path.append("./")') + self.tester.scapy_append('import sctp') + self.tester.scapy_append('from sctp import *') + self.tester.scapy_append('p = sniff(filter="ether src 52:00:00:00:00:00", iface="%s", count=%d)' % (rx_interface, len(packets_sent))) + self.tester.scapy_append('nr_packets=len(p)') + self.tester.scapy_append('reslist = [p[i].sprintf("%IP.chksum%;%TCP.chksum%;%UDP.chksum%;%SCTP.chksum%") for i in range(nr_packets)]') + self.tester.scapy_append('import string') + self.tester.scapy_append('RESULT = string.join(reslist, ",")') + + # Send packet. + self.tester.scapy_foreground() + self.tester.scapy_append('sys.path.append("./")') + self.tester.scapy_append('import sctp') + self.tester.scapy_append('from sctp import *') + + for packet_type in packets_sent.keys(): + self.tester.scapy_append('sendp([%s], iface="%s")' % (packets_sent[packet_type], tx_interface)) + + self.tester.scapy_execute() + out = self.tester.scapy_get_result() + packets_received = out.split(',') + self.verify(len(packets_sent) == len(packets_received), "Unexpected Packets Drop") + + for packet_received in packets_received: + ip_checksum, tcp_checksum, udp_checksup, sctp_checksum = packet_received.split(';') + + packet_type = '' + l4_checksum = '' + if tcp_checksum != '??': + packet_type = 'TCP' + l4_checksum = tcp_checksum + elif udp_checksup != '??': + packet_type = 'UDP' + l4_checksum = udp_checksup + elif sctp_checksum != '??': + packet_type = 'SCTP' + l4_checksum = sctp_checksum + + if ip_checksum != '??': + packet_type = 'IP/' + packet_type + if chksum[packet_type] != [ip_checksum, l4_checksum]: + result[packet_type] = packet_type + " checksum error" + else: + packet_type = 'IPv6/' + packet_type + if chksum[packet_type] != [l4_checksum]: + result[packet_type] = packet_type + " checksum error" + + return result + + def test_checksum_offload_with_vlan(self): + """ + Do not insert IPv4/IPv6 UDP/TCP checksum on the transmit packet. + Verify that the same number of packet are correctly received on the + traffic generator side. + Use VLAN label. + """ + dmac = self.dut.get_mac_address(self.dut_ports[1]) + pktsChkErr = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=1)/IP(chksum=0x0)/UDP(chksum=0x0)/("X"*46)' % dmac, + 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=2)/IP(chksum=0x0)/TCP(chksum=0x0)/("X"*46)' % dmac, + 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=3)/IP(chksum=0x0)/SCTP(chksum=0x0)/("X"*48)' % dmac, + 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=4)/IPv6()/UDP(chksum=0x0)/("X"*46)' % dmac, + 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=5)/IPv6()/TCP(chksum=0x0)/("X"*46)' % dmac} + + pkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/UDP()/("X"*46)' % dmac, + 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/TCP()/("X"*46)' % dmac, + 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/SCTP()/("X"*48)' % dmac, + 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/UDP()/("X"*46)' % dmac, + 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/TCP()/("X"*46)' % dmac} + + self.dut.send_expect("tx_checksum set 0xf %d" % self.dut_ports[0], "testpmd>") + + self.dut.send_expect("start", "testpmd>") + + result = self.checksum_validate(pktsChkErr, pkts) + + self.dut.send_expect("stop", "testpmd>") + + self.verify(len(result) == 0, string.join(result.values(), ",")) + + def test_checksum_offload_enable(self): + """ + Insert IPv4/IPv6 UDP/TCP/SCTP checksum on the transmit packet. + Enable Checksum offload. + Verify that the same number of packet are correctly received on the + traffic generator side. + """ + + dmac = self.dut.get_mac_address(self.dut_ports[1]) + + pkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/UDP()/("X"*46)' % dmac, + 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/TCP()/("X"*46)' % dmac, + 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/SCTP()/("X"*48)' % dmac, + 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/UDP()/("X"*46)' % dmac, + 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/TCP()/("X"*46)' % dmac} + + self.dut.send_expect("tx_checksum set 0xf %d" % self.dut_ports[0], "testpmd>") + + self.dut.send_expect("start", "testpmd>") + + result = self.checksum_validate(pkts, pkts) + + self.dut.send_expect("stop", "testpmd>") + + self.verify(len(result) == 0, string.join(result.values(), ",")) + + def test_checksum_offload_disable(self): + """ + Do not insert IPv4/IPv6 UDP/TCP checksum on the transmit packet. + Disable Checksum offload. + Verify that the same number of packet are correctly received on + the traffic generator side. + """ + + dmac = self.dut.get_mac_address(self.dut_ports[1]) + + sndIP = '10.0.0.1' + sndIPv6 = '::1' + sndPkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="%s")/UDP()/("X"*46)' % (dmac, sndIP), + 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="%s")/TCP()/("X"*46)' % (dmac, sndIP), + 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="%s")/UDP()/("X"*46)' % (dmac, sndIPv6), + 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="%s")/TCP()/("X"*46)' % (dmac, sndIPv6)} + + expIP = "11.0.0.1" + expIPv6 = '::1' + expPkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="%s")/UDP()/("X"*46)' % (dmac, expIP), + 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="%s")/TCP()/("X"*46)' % (dmac, expIP), + 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="%s")/UDP()/("X"*46)' % (dmac, expIPv6), + 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="%s")/TCP()/("X"*46)' % (dmac, expIPv6)} + + self.dut.send_expect("tx_checksum set 0x0 %d" % self.dut_ports[0], "testpmd>") + + self.dut.send_expect("start", "testpmd>") + result = self.checksum_validate(sndPkts, expPkts) + + self.verify(len(result) == 0, string.join(result.values(), ",")) + + self.dut.send_expect("stop", "testpmd>") + + def benchmark(self, lcore, ptype, mode, flow_format, size_list, nic): + """ + Test ans report checksum offload performance for given parameters. + """ + + Bps = dict() + Pps = dict() + Pct = dict() + dmac = self.dut.get_mac_address(self.dut_ports[0]) + + result = [2, lcore, ptype, mode] + for size in size_list: + + flow = flow_format % (dmac, size) + self.tester.scapy_append('wrpcap("test.pcap", [%s])' % flow) + + self.tester.scapy_execute() + + tgenInput = [] + tgenInput.append((self.tester.get_local_port(self.dut_ports[0]), self.tester.get_local_port(self.dut_ports[1]), "test.pcap")) + tgenInput.append((self.tester.get_local_port(self.dut_ports[1]), self.tester.get_local_port(self.dut_ports[0]), "test.pcap")) + + Bps[str(size)], Pps[str(size)] = self.tester.traffic_generator_throughput(tgenInput) + self.verify(Pps[str(size)] > 0, "No traffic detected") + Pps[str(size)] /= 1E6 + Pct[str(size)] = (Pps[str(size)] * 100) / self.wirespeed(self.nic, size, 2) + + result.append(Pps[str(size)]) + result.append(Pct[str(size)]) + + dcts.results_table_add_row(result) + + def test_perf_checksum_throughtput(self): + """ + Test checksum offload performance. + """ + + self.verify(self.nic == 'niantic', "throughtput case require niantic 10Gb self.nic") + # sizes = [64, 128, 256, 512, 1024] + sizes = [64, 128] + pkts = { + 'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/UDP()/("X"*(%d-46))', + 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/TCP()/("X"*(%d-58))', + 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/SCTP()/("X"*(%d-50+2))', + 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/UDP()/("X"* (lambda x: x - 66 if x > 66 else 0)(%d))', + 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/TCP()/("X"* (lambda x: x - 78 if x > 78 else 0)(%d))' + } + + lcore = "1S/2C/1T" + coreMask = dcts.create_mask(self.dut.get_core_list(lcore, socket=self.ports_socket)) + portMask = dcts.create_mask([self.dut_ports[0], self.dut_ports[1]]) + + for mode in ["sw", "hw"]: + self.logger.info("%s performance" % mode) + rst.write_text(mode + " Performance" + '\r\n') + tblheader = ["Ports", "S/C/T", "Packet Type", "Mode"] + for size in sizes: + tblheader.append("%sB mpps" % str(size)) + tblheader.append("%sB %% " % str(size)) + + dcts.results_table_add_header(tblheader) + + self.dut.send_expect("./%s/build/app/test-pmd/testpmd -c%s -n %d -- -i --nb-cores=1 --txpt=40 --txht=4 --txwt=0 --rxfreet=64 --mbcache=250 --portmask=%s" % (self.target, coreMask, self.dut.get_memory_channels(), portMask), "testpmd>", 120) + + self.dut.send_expect("set verbose 1", "testpmd> ") + self.dut.send_expect("set fwd csum", "testpmd> ") + + if mode == "hw": + self.dut.send_expect("tx_checksum set 0xf %d" % self.dut_ports[0], "testpmd> ") + self.dut.send_expect("tx_checksum set 0xf %d" % self.dut_ports[1], "testpmd> ") + else: + self.dut.send_expect("tx_checksum set 0x0 %d" % self.dut_ports[0], "testpmd> ") + self.dut.send_expect("tx_checksum set 0x0 %d" % self.dut_ports[1], "testpmd> ") + + self.dut.send_expect("start", "testpmd> ", 3) + + for ptype in pkts.keys(): + self.benchmark(lcore, ptype, mode, pkts[ptype], sizes, self.nic) + + self.dut.send_expect("stop", "testpmd> ") + self.dut.send_expect("quit", "#", 10) + dcts.results_table_print() + + def tear_down(self): + """ + Run after each test case. + """ + if self.dut.want_func_tests: + self.dut.send_expect("quit", "#") + + def tear_down_all(self): + """ + Run after each test suite. + """ + pass diff --git a/tests/TestSuite_cmdline.py b/tests/TestSuite_cmdline.py new file mode 100644 index 0000000..db3f205 --- /dev/null +++ b/tests/TestSuite_cmdline.py @@ -0,0 +1,124 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test cmdline. + +""" + +import dcts + + +from test_case import TestCase + +# +# +# Test class. +# + + +class TestCmdline(TestCase): + + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + Run at the start of each test suite. + + Cmdline Prerequisites: + cmdline build pass + At least one core in DUT + """ + out = self.dut.build_dpdk_apps('examples/cmdline') + self.verify('make: Leaving directory' in out, "Compilation failed") + self.verify("Error" not in out, "compilation error 1") + self.verify("No such file" not in out, "compilation error 2") + + # Run cmdline app + cores = self.dut.get_core_list('1S/1C/1T') + coreMask = dcts.create_mask(cores) + self.dut.send_expect("./examples/cmdline/build/app/cmdline -n 1 -c " + coreMask, "> ", 5) + + def set_up(self): + """ + Run before each test case. + Nothing to do. + """ + pass + + def test_cmdline_sample_commands(self): + """ + Sample commands test. + """ + + # add a test object with an IP address associated + out = self.dut.send_expect("add objtest 192.168.0.1", "example> ") + self.verify("Object objtest added, ip=192.168.0.1" in out, "add command error") + + # verify the object existance + out = self.dut.send_expect("add objtest 192.168.0.1", "example> ") + self.verify("Object objtest already exist" in out, "double add command error") + + # show the object result by 'show' command + out = self.dut.send_expect("show objtest", "example> ") + self.verify("Object objtest, ip=192.168.0.1" in out, "show command error") + + # delete the object in cmdline + out = self.dut.send_expect("del objtest", "example> ") + self.verify("Object objtest removed, ip=192.168.0.1" in out, "del command error") + + # double delete the object to verify the correctness + out = self.dut.send_expect("del objtest", "example> ", 1) + self.verify("Bad arguments" in out, "double del command error") + + # verify no such object anymore + out = self.dut.send_expect("show objtest", "example> ", 1) + self.verify("Bad arguments" in out, "final show command error") + + # verify the help command + out = self.dut.send_expect("help", "example> ", 1) + + """ + Demo example of command line interface in RTE + + This is a readline-like interface that can be used to + debug your RTE application. It supports some features + of GNU readline like completion, cut/paste, and some + other special bindings. + + This demo shows how rte_cmdline library can be + extended to handle a list of objects. There are + 3 commands: + - add obj_name IP + - del obj_name + - show obj_name + """ + self.verify(" " in out, "help command error") + + out = self.dut.send_expect("?", "example> ", 1) + """ + show [Mul-choice STRING]: Show/del an object + del [Mul-choice STRING]: Show/del an object + add [Fixed STRING]: Add an object (name, val) + help [Fixed STRING]: show help + """ + self.verify(" " in out, "? command error") + + def tear_down(self): + """ + Run after each test case. + Nothing to do. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + Stop cmdline app. + """ + self.dut.kill_all() diff --git a/tests/TestSuite_fdir.py b/tests/TestSuite_fdir.py new file mode 100644 index 0000000..61c7091 --- /dev/null +++ b/tests/TestSuite_fdir.py @@ -0,0 +1,335 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test 82599 Flow Director Support in DPDK +""" + +import dcts +import time + + +from test_case import TestCase + +# +# +# Test class. +# + + +class TestFdir(TestCase): + + # + # + # Utility methods and other non-test code. + # + + def send_and_verify(self, condition, packet): + """ + Send packages and verify behavior. + """ + self.tester.scapy_foreground() + self.tester.scapy_append('sys.path.append("./")') + self.tester.scapy_append('from sctp import *') + self.tester.scapy_append(packet) + self.dut.send_expect("start", "testpmd>") + self.tester.scapy_execute() + time.sleep(.5) + out = self.dut.send_expect("stop", "testpmd>") + if condition: + self.verify("PKT_RX_PKT_RX_FDIR" in out, "FDIR hash not displayed when required") + else: + self.verify("PKT_RX_PKT_RX_FDIR" not in out, "FDIR hash displayed when not required") + + # + # + # + # Test cases. + # + def set_up_all(self): + """ + Run at the start of each test suite. + """ + self.verify('bsdapp' not in self.target, "FDIR not support freebsd") + self.verify(self.nic in ["kawela", "niantic"], "NIC Unsupported: " + str(self.nic)) + + ports = self.dut.get_ports(self.nic) + self.verify(len(ports) >= 2, "Not enough ports available") + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_fdir_space(self): + """ + Setting memory reserved for FDir filters. + """ + + dutPorts = self.dut.get_ports(self.nic) + + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect --pkt-filter-size=64K" % self.target, "testpmd>", 120) + out = self.dut.send_expect("show port fdir %s" % dutPorts[0], "testpmd>") + self.dut.send_expect("quit", "# ", 30) + self.verify("free: 2048" in out, "Free space doesn't match the expected value") + + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect --pkt-filter-size=128K" % self.target, "testpmd>", 120) + out = self.dut.send_expect("show port fdir %s" % dutPorts[0], "testpmd>") + self.dut.send_expect("quit", "# ", 30) + self.verify("free: 4096" in out, "Free space doesn't match the expected value") + + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect --pkt-filter-size=256K" % self.target, "testpmd>", 120) + out = self.dut.send_expect("show port fdir %s" % dutPorts[0], "testpmd>") + self.dut.send_expect("quit", "# ", 30) + self.verify("free: 8192" in out, "Free space doesn't match the expected value") + + def test_fdir_signatures(self): + """ + FDir signature matching mode. + """ + + dutPorts = self.dut.get_ports(self.nic) + localPort = self.tester.get_local_port(dutPorts[0]) + itf = self.tester.get_interface(localPort) + + self.dut.kill_all() + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --portmask=%s --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect --pkt-filter-report-hash=none" % (self.target, dcts.create_mask([dutPorts[0]])), "testpmd>", 120) + self.dut.send_expect("set verbose 1", "testpmd>") + self.dut.send_expect("set fwd rxonly", "testpmd>") + self.dut.send_expect("set nbcore 3", "testpmd>") + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_perfect_filter %s udp src 192.168.0.1 1024 dst 192.168.0.2 1024 flexbytes 0x800 vlan 0 queue 1 soft 0x14" % dutPorts[0], "testpmd>") + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("quit", "# ", 30) + + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --portmask=%s --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect --pkt-filter-report-hash=match" % (self.target, dcts.create_mask([dutPorts[0]])), "testpmd>", 120) + self.dut.send_expect("set verbose 1", "testpmd>") + self.dut.send_expect("set fwd rxonly", "testpmd>") + self.dut.send_expect("set nbcore 3", "testpmd>") + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_perfect_filter %s udp src 192.168.0.1 1024 dst 192.168.0.2 1024 flexbytes 0x800 vlan 0 queue 1 soft 0x14" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("upd_perfect_filter %s udp src 192.168.1.1 0 dst 192.168.1.2 0 flexbytes 0x800 vlan 0 queue 1 soft 0x14" % dutPorts[0], "testpmd>") + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.1.1", dst="192.168.1.2")/UDP(sport=0,dport=0)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("rm_perfect_filter %s udp src 192.168.1.1 0 dst 192.168.1.2 0 flexbytes 0x800 vlan 0 soft 0x14" % dutPorts[0], "testpmd>") + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.1.1", dst="192.168.1.2")/UDP(sport=0,dport=0)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("quit", "# ", 30) + + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --portmask=%s --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect --pkt-filter-report-hash=always" % (self.target, dcts.create_mask([dutPorts[0]])), "testpmd>", 120) + self.dut.send_expect("set verbose 1", "testpmd>") + self.dut.send_expect("set fwd rxonly", "testpmd>") + self.dut.send_expect("set nbcore 3", "testpmd>") + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_perfect_filter %s udp src 192.168.0.1 1024 dst 192.168.0.2 1024 flexbytes 0x800 vlan 0 queue 1 soft 0x14" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("quit", "# ", 30) + + def test_fdir_matching(self): + """ + FDir matching mode + """ + + dutPorts = self.dut.get_ports(self.nic) + localPort = self.tester.get_local_port(dutPorts[0]) + itf = self.tester.get_interface(localPort) + + self.dut.kill_all() + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --portmask=%s --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=signature --pkt-filter-report-hash=match" % (self.target, dcts.create_mask([dutPorts[0]])), "testpmd>", 120) + self.dut.send_expect("set verbose 1", "testpmd>") + self.dut.send_expect("set fwd rxonly", "testpmd>") + self.dut.send_expect("set nbcore 3", "testpmd>") + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_signature_filter %s udp src 192.168.0.1 1024 dst 192.168.0.2 1024 flexbytes 0x800 vlan 0 queue 1" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/TCP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("upd_signature_filter %s udp src 192.168.1.1 0 dst 192.168.1.2 0 flexbytes 0x800 vlan 0 queue 1" % dutPorts[0], "testpmd>") + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.1.1", dst="192.168.1.2")/UDP(sport=0,dport=0)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("rm_signature_filter %s udp src 192.168.1.1 0 dst 192.168.1.2 0 flexbytes 0x800 vlan 0" % dutPorts[0], "testpmd>") + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.1.1", dst="192.168.1.2")/UDP(sport=0,dport=0)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_signature_filter %s tcp src 192.168.0.1 1024 dst 192.168.0.2 1024 flexbytes 0x800 vlan 0 queue 1" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/TCP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/SCTP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_signature_filter %s sctp src 192.168.0.1 0 dst 192.168.0.2 0 flexbytes 0x800 vlan 0 queue 1" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/SCTP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_signature_filter %s ip src 192.168.0.1 0 dst 192.168.0.2 0 flexbytes 0x800 vlan 0 queue 1" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")], iface="%s")' % (itf, itf)) + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IPv6(src="2001:0db8:85a3:0000:0000:8a2e:0370:7000", dst="2001:0db8:85a3:0000:0000:8a2e:0370:7338")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_signature_filter %s udp src 2001:0db8:85a3:0000:0000:8a2e:0370:7000 1024 dst 2001:0db8:85a3:0000:0000:8a2e:0370:7338 1024 flexbytes 0x86dd vlan 0 queue 1" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IPv6(src="2001:0db8:85a3:0000:0000:8a2e:0370:7000", dst="2001:0db8:85a3:0000:0000:8a2e:0370:7338")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("quit", "# ", 30) + + def test_fdir_perfect_matching(self): + """ + FDir perfect matching mode. + """ + + dutPorts = self.dut.get_ports(self.nic) + localPort = self.tester.get_local_port(dutPorts[0]) + itf = self.tester.get_interface(localPort) + + self.dut.kill_all() + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --portmask=%s --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect --pkt-filter-report-hash=match" % (self.target, dcts.create_mask([dutPorts[0]])), "testpmd>", 120) + self.dut.send_expect("set verbose 1", "testpmd>") + self.dut.send_expect("set fwd rxonly", "testpmd>") + self.dut.send_expect("set nbcore 3", "testpmd>") + + self.dut.send_expect("add_perfect_filter %s udp src 192.168.0.1 1024 dst 192.168.0.2 1024 flexbytes 0x800 vlan 0 queue 1 soft 0x14" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_perfect_filter %s tcp src 192.168.0.1 1024 dst 192.168.0.2 1024 flexbytes 0x800 vlan 0 queue 1 soft 0x15" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/TCP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_perfect_filter %s sctp src 192.168.0.1 0 dst 192.168.0.2 0 flexbytes 0x800 vlan 0 queue 1 soft 0x16" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/SCTP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_perfect_filter %s ip src 192.168.0.1 0 dst 192.168.0.2 0 flexbytes 0x800 vlan 0 queue 1 soft 0x17" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")], iface="%s")' % (itf, itf)) + + self.dut.send_expect("quit", "# ", 30) + + def test_fdir_filter_masks(self): + """ + FDir filter masks. + """ + + dutPorts = self.dut.get_ports(self.nic) + localPort = self.tester.get_local_port(dutPorts[0]) + itf = self.tester.get_interface(localPort) + + self.dut.kill_all() + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --portmask=%s --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect --pkt-filter-size=64K --pkt-filter-report-hash=match" % (self.target, dcts.create_mask([dutPorts[0]])), "testpmd>", 120) + self.dut.send_expect("set verbose 1", "testpmd>") + self.dut.send_expect("set fwd rxonly", "testpmd>") + self.dut.send_expect("set nbcore 3", "testpmd>") + + self.dut.send_expect("set_masks_filter %s only_ip_flow 0 src_mask 0xffffff00 0xffff dst_mask 0xffffff00 0xffff flexbytes 1 vlan_id 1 vlan_prio 1" % dutPorts[0], "testpmd>") + self.dut.send_expect("add_perfect_filter %s udp src 192.168.0.0 1024 dst 192.168.0.0 1024 flexbytes 0x800 vlan 0 queue 1 soft 0x17" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.15", dst="192.168.0.15")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.1.1")/UDP(sport=1024,dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("set_masks_filter %s only_ip_flow 0 src_mask 0xffffffff 0xff00 dst_mask 0xffffffff 0xff00 flexbytes 1 vlan_id 1 vlan_prio 1" % dutPorts[0], "testpmd>") + self.dut.send_expect("add_perfect_filter %s udp src 10.11.12.1 0x4400 dst 10.11.12.2 0x4500 flexbytes 0x800 vlan 0 queue 1 soft 0x4" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="10.11.12.1", dst="10.11.12.2")/UDP(sport=0x4400,dport=0x4500)], iface="%s")' % (itf, itf)) + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="10.11.12.1", dst="10.11.12.2")/UDP(sport=0x4411,dport=0x4517)], iface="%s")' % (itf, itf)) + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="10.11.12.1", dst="10.11.12.2")/UDP(sport=0x4500,dport=0x5500)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("set_masks_filter %s only_ip_flow 1 src_mask 0xffffffff 0x0 dst_mask 0xffffffff 0x0 flexbytes 1 vlan_id 1 vlan_prio 1" % dutPorts[0], "testpmd>") + self.dut.send_expect("add_perfect_filter %s ip src 192.168.0.1 0 dst 192.168.0.2 0 flexbytes 0x800 vlan 0 queue 1 soft 0x42" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024, dport=1024)], iface="%s")' % (itf, itf)) + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/TCP(sport=1024, dport=1024)], iface="%s")' % (itf, itf)) + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/SCTP(sport=1024, dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("quit", "# ", 30) + + def test_fdir_flexbytes_filtering(self): + """ + FDir flexbytes filtering + """ + + dutPorts = self.dut.get_ports(self.nic) + localPort = self.tester.get_local_port(dutPorts[0]) + itf = self.tester.get_interface(localPort) + + self.dut.kill_all() + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --portmask=%s --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect --pkt-filter-size=64K --pkt-filter-report-hash=match --pkt-filter-flexbytes-offset=18" % (self.target, dcts.create_mask([dutPorts[0]])), "testpmd>", 120) + self.dut.send_expect("set verbose 1", "testpmd>") + self.dut.send_expect("set fwd rxonly", "testpmd>") + self.dut.send_expect("set nbcore 3", "testpmd>") + + self.dut.send_expect("add_perfect_filter %s ip src 192.168.0.1 0 dst 192.168.0.2 0 flexbytes 0x1 vlan 0 queue 1 soft 0x1" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/GRE(proto=0x1)/IP()/UDP()], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_perfect_filter %s ip src 192.168.0.1 0 dst 192.168.0.2 0 flexbytes 0xff vlan 0 queue 1 soft 0xff" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/GRE(proto=0xff)/IP()/UDP()], iface="%s")' % (itf, itf)) + + self.dut.send_expect("set_masks_filter %s only_ip_flow 0 src_mask 0xffffffff 0xffff dst_mask 0xffffffff 0xffff flexbytes 0 vlan_id 1 vlan_prio 1" % dutPorts[0], "testpmd>") + self.dut.send_expect("add_perfect_filter %s ip src 192.168.0.1 0 dst 192.168.0.2 0 flexbytes 0x0 vlan 0 queue 1 soft 0x42" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/GRE(proto=0x1)/IP()/UDP()], iface="%s")' % (itf, itf)) + + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/IP(src="192.168.0.1", dst="192.168.0.2")/GRE(proto=0xFF)/IP()/UDP()], iface="%s")' % (itf, itf)) + + self.dut.send_expect("quit", "# ", 30) + + def test_fdir_vlanfiltering(self): + """ + FDir VLAN field filtering + """ + + dutPorts = self.dut.get_ports(self.nic) + localPort = self.tester.get_local_port(dutPorts[0]) + itf = self.tester.get_interface(localPort) + + self.dut.kill_all() + self.dut.send_expect("./%s/app/testpmd -c 0xff -n 1 -- -i --portmask=%s --nb-cores=2 --rxq=2 --txq=2 --disable-rss --pkt-filter-mode=perfect" % (self.target, dcts.create_mask([dutPorts[0]])), "testpmd>", 120) + self.dut.send_expect("set verbose 1", "testpmd>") + self.dut.send_expect("set fwd rxonly", "testpmd>") + # "rx_vlan add all" has been removed from testpmd + self.dut.send_expect("rx_vlan add 0xFFF %s" % dutPorts[0], "testpmd>") + self.dut.send_expect("rx_vlan add 0x001 %s" % dutPorts[0], "testpmd>") + self.dut.send_expect("rx_vlan add 0x017 %s" % dutPorts[0], "testpmd>") + + self.send_and_verify(False, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/Dot1Q(vlan=0x0FFF)/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024, dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("add_perfect_filter %s udp src 192.168.0.1 1024 dst 192.168.0.2 1024 flexbytes 0x8100 vlan 0xfff queue 1 soft 0x47" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/Dot1Q(vlan=0x0FFF)/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024, dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("set_masks_filter %s only_ip_flow 0 src_mask 0xffffffff 0xffff dst_mask 0xffffffff 0xffff flexbytes 1 vlan_id 0 vlan_prio 0" % dutPorts[0], "testpmd>") + self.dut.send_expect("add_perfect_filter %s udp src 192.168.0.1 1024 dst 192.168.0.2 1024 flexbytes 0x8100 vlan 0 queue 1 soft 0x47" % dutPorts[0], "testpmd>") + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/Dot1Q(vlan=0x001)/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024, dport=1024)], iface="%s")' % (itf, itf)) + self.send_and_verify(True, 'sendp([Ether(src=get_if_hwaddr("%s"), dst="00:1B:21:8E:B2:30")/Dot1Q(vlan=0x0017)/IP(src="192.168.0.1", dst="192.168.0.2")/UDP(sport=1024, dport=1024)], iface="%s")' % (itf, itf)) + + self.dut.send_expect("quit", "# ", 30) + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + pass diff --git a/tests/TestSuite_hello_world.py b/tests/TestSuite_hello_world.py new file mode 100644 index 0000000..3633ed7 --- /dev/null +++ b/tests/TestSuite_hello_world.py @@ -0,0 +1,86 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test HelloWorld example. +""" + +import dcts +from test_case import TestCase + +# +# +# Test class. +# + + +class TestHelloWorld(TestCase): + + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + Run at the start of each test suite. + hello_world Prerequistites: + helloworld build pass + """ + out = self.dut.build_dpdk_apps('examples/helloworld') + + self.verify("Error" not in out, "compilation error 1") + self.verify("No such file" not in out, "compilation error 2") + + def set_up(self): + """ + Run before each test case. + Nothing to do. + """ + pass + + def test_hello_world_single_core(self): + """ + Run hello world on single lcores + Only received hello message from core0 + """ + + # get the mask for the first core + cores = self.dut.get_core_list('1S/1C/1T') + coreMask = dcts.create_mask(cores) + cmdline = "./examples/helloworld/build/app/helloworld -n 1 -c " + coreMask + out = self.dut.send_expect(cmdline, "# ", 3) + + self.verify("hello from core %s" % cores[0] in out, "EAL not started on core%s" % cores[0]) + + def test_hello_world_all_cores(self): + """ + Run hello world on all lcores + Received hello message from all lcores + """ + + # get the maximun logical core number + cores = self.dut.get_core_list('all') + coreMask = dcts.create_mask(cores) + + cmdline = "./examples/helloworld/build/app/helloworld -n 1 -c " + coreMask + out = self.dut.send_expect(cmdline, "# ", 5) + + for i in range(len(cores)): + self.verify("hello from core %s" % cores[i] in out, "EAL not started on core%s" % cores[i]) + + def tear_down(self): + """ + Run after each test case. + Nothing to do. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + Nothing to do. + """ + pass diff --git a/tests/TestSuite_ieee1588.py b/tests/TestSuite_ieee1588.py new file mode 100644 index 0000000..09c1729 --- /dev/null +++ b/tests/TestSuite_ieee1588.py @@ -0,0 +1,145 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test support of IEEE1588 Precise Time Protocol. +""" + +import dcts +import time + + +from test_case import TestCase + +# +# +# Test class. +# + + +class TestIeee1588(TestCase): + + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + Run at the start of each test suite. + + + IEEE1588 Prerequisites + """ + + dutPorts = self.dut.get_ports(self.nic) + self.verify(len(dutPorts) > 0, "No ports found for " + self.nic) + + # Change the config file to support IEEE1588 and recompile the package. + if "bsdapp" in self.target: + self.dut.send_expect("sed -i -e 's/IEEE1588=n$/IEEE1588=y/' config/common_bsdapp", "# ", 30) + else: + self.dut.send_expect("sed -i -e 's/IEEE1588=n$/IEEE1588=y/' config/common_linuxapp", "# ", 30) + self.dut.skip_setup = False + self.dut.build_install_dpdk(self.target) + + self.dut.send_expect("./%s/app/testpmd -c ffffff -n 3 -- -i --rxpt=0 --rxht=0 --rxwt=0 --txpt=39 --txht=0 --txwt=0" % self.target, + "testpmd> ", 100) + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_ieee1588_enable(self): + """ + IEEE1588 Enable test case. + """ + + self.dut.send_expect("set fwd ieee1588", "testpmd> ") + self.dut.send_expect("start", ">", 5) # Waiting for 'testpmd> ' Fails due to log messages, "Received non PTP packet", in the output + time.sleep(1) # Allow the output from the "start" command to finish before looking for a regexp in expect + + # use the first port on that self.nic + dutPorts = self.dut.get_ports(self.nic) + port = self.tester.get_local_port(dutPorts[0]) + itf = self.tester.get_interface(port) + + self.tester.scapy_background() + self.tester.scapy_append('p = sniff(iface="%s", count=2)' % itf) + self.tester.scapy_append('RESULT = p[1].summary()') + + # this is the output of sniff + # [<Ether dst=01:1b:19:00:00:00 src=00:00:00:00:00:00 type=0x88f7 |<Raw load='\x00\x02' |>>] + + self.tester.scapy_foreground() + self.tester.scapy_append('nutmac="01:1b:19:00:00:00"') + self.tester.scapy_append('sendp([Ether(dst=nutmac,type=0x88f7)/"\\x00\\x02"], iface="%s")' % itf) + self.tester.scapy_append('time.sleep(1)') + + self.tester.scapy_execute() + out = self.tester.scapy_get_result() + self.verify("0x88f7" in out, "Ether type is not PTP") + # self.verify("\\x00\\x02" in out, "Payload wrong in PTP") + + time.sleep(1) + out = self.dut.send_expect("stop", "testpmd> ") + + text = dcts.regexp(out, "(.*) by hardware") + self.verify("IEEE1588 PTP V2 SYNC" in text, "Not filtered " + text) + + rx_time = dcts.regexp(out, "RX timestamp value (0x[0-9a-fA-F]+)") + tx_time = dcts.regexp(out, "TX timestamp value (0x[0-9a-fA-F]+)") + + self.verify(rx_time is not None, "RX timestamp error ") + self.verify(tx_time is not None, "TX timestamp error ") + self.verify(int(tx_time, 16) > int(rx_time, 16), "Timestamp mismatch") + + def test_ieee1588_disable(self): + """ + IEEE1588 Disable test case. + """ + + self.dut.send_expect("stop", "testpmd> ") + time.sleep(3) + + # use the first port on that self.nic + dutPorts = self.dut.get_ports(self.nic) + port = self.tester.get_local_port(dutPorts[0]) + itf = self.tester.get_interface(port) + + self.tester.scapy_background() + self.tester.scapy_append('p = sniff(iface="%s", count=2, timeout=1)' % itf) + self.tester.scapy_append('RESULT = p[1].summary()') + + self.tester.scapy_foreground() + self.tester.scapy_append('nutmac="01:1b:19:00:00:00"') + self.tester.scapy_append('sendp([Ether(dst=nutmac,type=0x88f7)/"\\x00\\x02"], iface="%s")' % itf) + + self.tester.scapy_execute() + time.sleep(2) + + out = self.tester.scapy_get_result() + self.verify("Ether" not in out, "Ether type is not PTP") + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + self.dut.send_expect("quit", "# ", 30) + + # Restore the config file and recompile the package. + if "bsdapp" in self.target: + self.dut.send_expect("sed -i -e 's/IEEE1588=y$/IEEE1588=n/' config/common_bsdapp", "# ", 30) + else: + self.dut.send_expect("sed -i -e 's/IEEE1588=y$/IEEE1588=n/' config/common_linuxapp", "# ", 30) + self.dut.build_install_dpdk(self.target) diff --git a/tests/TestSuite_ip_pipeline.py b/tests/TestSuite_ip_pipeline.py new file mode 100644 index 0000000..5fade77 --- /dev/null +++ b/tests/TestSuite_ip_pipeline.py @@ -0,0 +1,567 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test userland 10Gb PMD + +""" + +from scapy.layers.inet import Ether, IP, TCP +from scapy.utils import struct, socket, PcapWriter +from settings import HEADER_SIZE +from test_case import TestCase +from time import sleep +import dcts + +# +# +# Test class. +# + + +class TestIPPipeline(TestCase): + + # + # + # Utility methods and other non-test code. + # + payload_watermark = 'TestPF' + + frame_sizes = [64, 65, 128, 1024] + """Sizes of the frames to be sent""" + + number_of_frames = [1, 3, 63, 64, 65, 127, 128] + """Number of frames in the pcap file to be created""" + + incremental_ip_address = [True, False] + """True if the IP address is incremented in the frames""" + + inter = [0, 0.7] + """Interval between frames sent in seconds""" + + dummy_pcap = 'dummy.pcap' + + def increment_ip_addr(self, ip_address, increment): + + ip2int = lambda ipstr: struct.unpack('!I', socket.inet_aton(ipstr))[0] + x = ip2int(ip_address) + int2ip = lambda n: socket.inet_ntoa(struct.pack('!I', n)) + return int2ip(x + increment) + + def create_tcp_ipv4_frame( + self, ip_id, src_ip_addr, dst_ip_addr, frame_size, + src_mac_addr='00:00:0A:00:0B:00', + dst_mac_addr='00:00:0A:00:0A:00'): + + payload_size = frame_size - HEADER_SIZE['eth'] - HEADER_SIZE['ip'] -\ + HEADER_SIZE['tcp'] - \ + len(TestIPPipeline.payload_watermark) + + if payload_size < 0: + payload_size = 0 + + frame = Ether() / IP() / TCP(flags="") / (TestIPPipeline.payload_watermark + + "X" * payload_size) + frame[Ether].src = src_mac_addr + frame[Ether].dst = dst_mac_addr + + frame[IP].src = src_ip_addr + frame[IP].dst = dst_ip_addr + frame[IP].id = ip_id + + # TCP ports always 0 + frame[TCP].sport = 0 + frame[TCP].dport = 0 + + return frame + + def create_pcap_file_from_frames(self, file_name, frames): + + writer = PcapWriter(file_name, append=False) + + for frame in frames: + writer.write(frame) + + writer.close() + + def create_pcap_file(self, file_name, frame_size, number_of_frames, + incremental_ip_address, + src_ip="0.0.0.0", + dst_ip="0.0.0.0"): + + current_frame = 0 + writer = PcapWriter(file_name, append=False) + + while current_frame < number_of_frames: + ip_id = 0 # current_frame % 0x10000 + + frame = self.create_tcp_ipv4_frame(ip_id, src_ip, dst_ip, + frame_size) + writer.write(frame) + + if incremental_ip_address: + dst_ip = self.increment_ip_addr(dst_ip, 1) + + current_frame += 1 + + writer.close() + + def enable_pmd_pcap(self, enable=True): + + if enable: + self.dut.send_expect( + "sed -i 's/CONFIG_RTE_LIBRTE_PMD_PCAP=n$/CONFIG_RTE_LIBRTE_PMD_PCAP=y/' config/defconfig_%s" % self.target, "# ") + else: + self.dut.send_expect( + "sed -i 's/CONFIG_RTE_LIBRTE_PMD_PCAP=y$/CONFIG_RTE_LIBRTE_PMD_PCAP=n/' config/defconfig_%s" % self.target, "# ") + + self.dut.build_install_dpdk(self.target) + out = self.dut.build_dpdk_apps("./examples/ip_pipeline") + self.verify("Error" not in out, "Compilation error") + self.dut.bind_interfaces_linux() + + def start_ip_pipeline(self, ports): + command_line = "./examples/ip_pipeline/build/ip_pipeline -c %s -n %d -- -p %s" % \ + (self.coremask, + self.dut.get_memory_channels(), + ports) + + out = self.dut.send_expect(command_line, 'pipeline>', 60) + sleep(5) # 'Initialization completed' is not the last output, some + # seconds are still needed for init. + + self.verify("Aborted" not in out, "Error starting ip_pipeline") + self.verify("PANIC" not in out, "Error starting ip_pipeline") + self.verify("ERROR" not in out, "Error starting ip_pipeline") + + def start_ip_pipeline_pcap(self, pcap0_file, pcap1_file): + + pcap_config = "'eth_pcap0;rx_pcap=/root/%s;tx_pcap=/tmp/port0out.pcap,eth_pcap1;rx_pcap=/root/%s;tx_pcap=/tmp/port1out.pcap'" % ( + pcap0_file, + pcap1_file) + + command_line = "./examples/ip_pipeline/build/ip_pipeline -c %s -n %d --use-device %s -- -p 0x3" % \ + (self.coremask, + self.dut.get_memory_channels(), + pcap_config) + + out = self.dut.send_expect(command_line, 'pipeline>', 60) + sleep(5) # 'Initialization completed' is not the last output, some + # seconds are still needed for init. + + self.verify("Aborted" not in out, "Error starting ip_pipeline") + self.verify("PANIC" not in out, "Error starting ip_pipeline") + + def quit_ip_pipeline(self): + self.dut.send_expect("quit", "# ", 5) + + def tcpdump_start_sniffing(self, ifaces=[]): + """ + Starts tcpdump in the background to sniff the tester interface where + the packets are transmitted to and from the self.dut. + All the captured packets are going to be stored in a file for a + post-analysis. + """ + + for iface in ifaces: + command = ( + 'tcpdump -w tcpdump_{0}.pcap -i {0} 2>tcpdump_{0}.out &').format(iface) + self.tester.send_expect( + 'rm -f tcpdump_{0}.pcap', '#').format(iface) + self.tester.send_expect(command, '#') + + def tcpdump_stop_sniff(self): + """ + Stops the tcpdump process running in the background. + """ + + self.tester.send_expect('killall tcpdump', '#') + # For the [pid]+ Done tcpdump... message after killing the process + sleep(1) + self.tester.send_expect('echo "Cleaning buffer"', '#') + sleep(1) + + def tcpdump_command(self, command, machine): + """ + Sends a tcpdump related command and returns an integer from the output + """ + + if machine == 'dut': + result = self.dut.send_expect(command, '#', alt_session=True) + else: + result = self.tester.send_expect(command, '#', alt_session=True) + + return int(result.strip()) + + def number_of_packets(self, file_name, machine='tester'): + """ + By reading the file generated by tcpdump it counts how many packets were + forwarded by the sample app and received in the self.tester. The sample app + will add a known MAC address for the test to look for. + """ + + command = ('tcpdump -A -nn -e -v -r %s 2>/dev/null | grep -c "%s"' % + (file_name, TestIPPipeline.payload_watermark)) + return int(self.tcpdump_command(command, machine)) + + def send_and_sniff_pcap_file(self, pcap_file, frames_number, from_port, + to_port, inter=0): + """ + Sent frames_number frames from the pcap_file with inter seconds of + interval. + Returns the number of received frames. + """ + + tx_port = self.tester.get_local_port(self.dut_ports[from_port]) + rx_port = self.tester.get_local_port(self.dut_ports[to_port]) + + tx_interface = self.tester.get_interface(tx_port) + rx_interface = self.tester.get_interface(rx_port) + + self.tcpdump_start_sniffing([tx_interface, rx_interface]) + + self.dut.send_expect('link 0 up', 'pipeline>') + self.dut.send_expect('link 1 up', 'pipeline>') + + timeout = frames_number * inter + 2 + inter = ", inter=%d" % inter + + # Prepare the frames to be sent + self.tester.scapy_foreground() + self.tester.scapy_append('p = rdpcap("%s")' % (pcap_file)) + self.tester.scapy_append( + 'sendp(p[:%s], iface="%s" %s)' % (frames_number, + tx_interface, + inter)) + + # Execute scapy to sniff sniffing and send the frames + self.tester.scapy_execute(timeout) + + self.tcpdump_stop_sniff() + + self.dut.send_expect('link 0 down', 'pipeline>') + self.dut.send_expect('link 1 down', 'pipeline>') + + rx_stats = self.number_of_packets('tcpdump_%s.pcap' % rx_interface) + tx_stats = self.number_of_packets('tcpdump_%s.pcap' % tx_interface) + + # Do not count the sent frames in the tx_interface + tx_stats = tx_stats - frames_number + + return {'rx': rx_stats, 'tx': tx_stats} + + def check_results(self, stats, expected): + """ + This function check that the Rx and Tx stats matches the expected. + expected = [Rx, Tx] + """ + + for port in ['rx', 'tx']: + self.verify(stats[port] == expected[port], + 'Frames expected (%s) and received (%s) mismatch on %s port' % ( + expected[ + port], + stats[ + port], + port)) + + def pipeline_command(self, command): + out = self.dut.send_expect(command, 'pipeline>') + self.verify("Illegal" not in out, "Pipeline command error 1: '%s'" % command) + self.verify("Bad" not in out, "Pipeline command error 2: '%s'" % command) + return out + + def pipeline_add_flow(self, port, src_ip, dst_ip, src_port, dst_port, + protocol=6): + command = 'flow add %s %s %d %d %d %d' % (src_ip, dst_ip, src_port, + dst_port, protocol, port) + out = self.pipeline_command(command) + self.verify("Adding flow" in out, "Add flow error") + + def pipeline_del_flow(self, src_ip, dst_ip, src_port, dst_port, + protocol=6): + command = 'flow del %s %s %d %d %d' % (src_ip, dst_ip, src_port, + dst_port, protocol) + out = self.pipeline_command(command) + self.verify("Deleting flow" in out, "Del flow error") + + def pipeline_add_route(self, port, src_ip, netmask, gw_ip): + command = 'route add %s %d %d %s' % (src_ip, netmask, port, gw_ip) + out = self.pipeline_command(command) + self.verify("Adding route" in out, "Add route error") + + def pipeline_del_route(self, src_ip, netmask): + command = 'route del %s %d' % (src_ip, netmask) + out = self.pipeline_command(command) + self.verify("Deleting route" in out, "Del route error") + + def pipeline_traffic_burst(self): + self.dut.send_expect('link 0 up', 'pipeline>') + self.dut.send_expect('link 1 up', 'pipeline>') + sleep(0.1) + self.dut.send_expect('link 0 down', 'pipeline>') + self.dut.send_expect('link 1 down', 'pipeline>') + + # + # + # + # Test cases. + # + def set_up_all(self): + """ + Run at the start of each test suite. + + PMD prerequisites. + """ + + # Check for port availability + self.needed_ports = {"niantic": 2} + self.dut_ports = self.dut.get_ports(self.nic) + self.verify(len(self.dut_ports) >= self.needed_ports[self.nic], + "Insufficient ports for speed testing") + + # Enable the support for PCAP Driver + self.enable_pmd_pcap() + out = self.dut.build_dpdk_apps("./examples/ip_pipeline") + self.verify("Error" not in out, "Compilation error") + + self.ports_mask = dcts.create_mask( + [self.dut_ports[0], self.dut_ports[1]]) + self.coremask = "0x3e" # IP Pipeline app requires FIVE cores + + self.dut.setup_memory(4096) + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_incremental_ip(self): + """ + Testing that frames with incremental IP addresses pass through the + pipeline regardless the frames_number and the speed. + """ + pcap_file = 'ip_pipeline.pcap' + frame_size = 64 + + self.start_ip_pipeline(ports=self.ports_mask) + self.dut.send_expect( + 'run examples/ip_pipeline/ip_pipeline.sh', 'pipeline>', 10) + + # Create a PCAP file containing the maximum frames_number of frames needed + # with fixed size and incremental IP + self.create_pcap_file(pcap_file, frame_size, + max(TestIPPipeline.number_of_frames), True) + self.tester.session.copy_file_to(pcap_file) + + for frames_number in TestIPPipeline.number_of_frames: + for inter in TestIPPipeline.inter: + print dcts.BLUE( + "\tNumber of frames %d, interval %.1f" % (frames_number, + inter)) + stats = self.send_and_sniff_pcap_file(pcap_file, frames_number, + 1, 0, inter) + + expected = {'tx': 0, 'rx': frames_number} + self.check_results(stats, expected) + + stats = self.send_and_sniff_pcap_file(pcap_file, frames_number, + 0, 1, inter) + + expected = {'tx': frames_number, 'rx': 0} + self.check_results(stats, expected) + + def test_frame_sizes(self): + """ + Testing that frames with different sizes pass through the pipeline. + """ + pcap_file = 'ip_pipeline.pcap' + frames_number = 100 + inter = 0.5 + + self.start_ip_pipeline(ports=self.ports_mask) + self.dut.send_expect( + 'run examples/ip_pipeline/ip_pipeline.sh', 'pipeline>', 10) + + for frame_size in TestIPPipeline.frame_sizes: + + # Create a PCAP file containing the fixed number of frames above + # with variable size and incremental IP + self.create_pcap_file(pcap_file, frame_size, 100, True) + self.tester.session.copy_file_to(pcap_file) + + print dcts.BLUE("\tFrame size %d, interval %.1f" % (frame_size, + inter)) + + stats = self.send_and_sniff_pcap_file(pcap_file, frames_number, + 1, 0, inter) + + expected = {'tx': 0, 'rx': frames_number} + self.check_results(stats, expected) + + stats = self.send_and_sniff_pcap_file(pcap_file, frames_number, + 0, 1, inter) + + expected = {'tx': frames_number, 'rx': 0} + self.check_results(stats, expected) + + def test_flow_management(self): + """ + Add several flows and check only frames with matching IPs passes + """ + pcap_file = 'ip_pipeline.pcap' + frame_size = 64 + + default_setup = ['arp add 0 0.0.0.1 0a:0b:0c:0d:0e:0f', + 'arp add 1 0.128.0.1 1a:1b:1c:1d:1e:1f', + 'route add 0.0.0.0 9 0 0.0.0.1', + 'route add 0.128.0.0 9 1 0.128.0.1'] + + ip_addrs = [ + '0.0.0.0', '0.0.0.1', '0.0.0.127', '0.0.0.128', '0.0.0.255', + '0.0.1.0', '0.0.127.0', '0.0.128.0', '0.0.129.0', '0.0.255.0', + '0.127.0.0', '0.127.1.0', '0.127.127.0', '0.127.255.0', + '0.127.255.255'] + + frames = [] + + for addr in ip_addrs: + frames.append(self.create_tcp_ipv4_frame(0, '0.0.0.0', addr, + frame_size)) + + self.create_pcap_file_from_frames(pcap_file, frames) + self.tester.session.copy_file_to(pcap_file) + + # Start ip_pipeline app and setup defaults + self.start_ip_pipeline(ports=self.ports_mask) + for command in default_setup: + self.pipeline_command(command) + + # Check that no traffic pass though + stats = self.send_and_sniff_pcap_file(pcap_file, len(frames), + 1, 0, 0.2) + expected = {'tx': 0, 'rx': 0} + self.check_results(stats, expected) + + # Add the flows + flows_added = 0 + for addrs in ip_addrs: + self.pipeline_add_flow(1, '0.0.0.0', addrs, 0, 0) + flows_added += 1 + + # Check that traffic matching flows pass though + stats = self.send_and_sniff_pcap_file(pcap_file, len(frames), + 1, 0, 0.2) + expected = {'tx': 0, 'rx': flows_added} + self.check_results(stats, expected) + + # Remove flows + for addrs in ip_addrs: + self.pipeline_del_flow('0.0.0.0', addrs, 0, 0) + flows_added -= 1 + + # Check that traffic matching flows pass though + stats = self.send_and_sniff_pcap_file(pcap_file, len(frames), + 1, 0, 0.2) + expected = {'tx': 0, 'rx': flows_added} + self.check_results(stats, expected) + + out = self.dut.send_expect('flow print', 'pipeline>') + self.verify("=> Port =" not in out, "Flow found after deletion") + + # Check that again no traffic pass though + stats = self.send_and_sniff_pcap_file(pcap_file, len(frames), + 1, 0, 0.2) + expected = {'tx': 0, 'rx': 0} + self.check_results(stats, expected) + + self.quit_ip_pipeline() + + def test_route_management(self): + """ + Add several flows and check only frames with matching IPs passes + """ + pcap_file = 'ip_pipeline.pcap' + frame_size = 64 + + default_setup = ['arp add 0 0.0.0.1 0a:0b:0c:0d:0e:0f', + 'arp add 1 0.128.0.1 1a:1b:1c:1d:1e:1f', + 'flow add all'] + + ip_addrs = [ + '0.0.0.0', '0.0.0.1', '0.0.0.127', '0.0.0.128', '0.0.0.255', + '0.0.1.0', '0.0.127.0', '0.0.128.0', '0.0.129.0', '0.0.255.0', + '0.127.0.0', '0.127.1.0', '0.127.127.0', '0.127.255.0', + '0.127.255.255'] + + frames = [] + + for addr in ip_addrs: + frames.append(self.create_tcp_ipv4_frame(0, '0.0.0.0', addr, + frame_size)) + + self.create_pcap_file_from_frames(pcap_file, frames) + self.tester.session.copy_file_to(pcap_file) + + # Start ip_pipeline app and setup defaults + self.start_ip_pipeline(ports=self.ports_mask) + for command in default_setup: + self.pipeline_command(command) + + # Check that no traffic pass though + stats = self.send_and_sniff_pcap_file(pcap_file, len(frames), + 1, 0, 0.2) + expected = {'tx': 0, 'rx': 0} + self.check_results(stats, expected) + + # Add the routes + routes_added = 0 + for addr in ip_addrs: + self.pipeline_add_route(0, addr, 32, '0.0.0.1') + routes_added += 1 + + # Check that traffic matching routes pass though + stats = self.send_and_sniff_pcap_file(pcap_file, len(frames), + 1, 0, 0.2) + + expected = {'tx': 0, 'rx': routes_added} + self.check_results(stats, expected) + + # Remove routes + for addr in ip_addrs: + self.pipeline_del_route(addr, 32) + routes_added -= 1 + + # Check that traffic matching flows pass though + stats = self.send_and_sniff_pcap_file(pcap_file, len(frames), + 1, 0, 0.2) + expected = {'tx': 0, 'rx': routes_added} + self.check_results(stats, expected) + + out = self.dut.send_expect('route print', 'pipeline>') + self.verify("Destination = " not in out, "Route found after deletion") + + # Check that again no traffic pass though + stats = self.send_and_sniff_pcap_file(pcap_file, len(frames), + 1, 0, 0.2) + expected = {'tx': 0, 'rx': 0} + self.check_results(stats, expected) + + self.quit_ip_pipeline() + + def tear_down(self): + """ + Run after each test case. + """ + self.quit_ip_pipeline() + + def tear_down_all(self): + """ + Run after each test suite. + """ + # Disable the support for PCAP Driver + # self.enable_pmd_pcap(False) + out = self.dut.build_dpdk_apps("./examples/ip_pipeline") + self.verify("Error" not in out, "Compilation error") diff --git a/tests/TestSuite_ipfrag.py b/tests/TestSuite_ipfrag.py new file mode 100644 index 0000000..8f33f7c --- /dev/null +++ b/tests/TestSuite_ipfrag.py @@ -0,0 +1,381 @@ +""" +DPDK Test suite. + +Test IPv4 fragmentation features in DPDK. + +""" + +import dcts +import string +import re + +lpm_table_ipv4 = [ + "{IPv4(100,10,0,0), 16, P2}", + "{IPv4(100,20,0,0), 16, P2}", + "{IPv4(100,30,0,0), 16, P0}", + "{IPv4(100,40,0,0), 16, P0}", + "{IPv4(100,50,0,0), 16, P2}", + "{IPv4(100,60,0,0), 16, P2}", + "{IPv4(100,70,0,0), 16, P0}", + "{IPv4(100,80,0,0), 16, P0}", +] + +lpm_table_ipv6 = [ + "{{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, P2}", + "{{2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, P2}", + "{{3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, P0}", + "{{4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, P0}", + "{{5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, P2}", + "{{6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, P2}", + "{{7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, P0}", + "{{8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, P0}", +] + +from test_case import TestCase + +# +# +# Test class. +# + + +class TestIpfrag(TestCase): + + def portRepl(self, match): + """ + Function to replace P([0123]) pattern in tables + """ + + portid = match.group(1) + self.verify(int(portid) in range(4), "invalid port id") + return '%s' % eval("P" + str(portid)) + # + # + # Utility methods and other non-test code. + # + # Insert or move non-test functions here. + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + ip_fragmentation Prerequisites + """ + + # Based on h/w type, choose how many ports to use + ports = self.dut.get_ports(self.nic) + print ports + + # Verify that enough ports are available + self.verify(len(ports) >= 4, "Insufficient ports for testing") + + self.ports_socket = self.dut.get_numa_id(ports[0]) + + # Verify that enough threads are available + cores = self.dut.get_core_list("2S/2C/2T") + self.verify(cores is not None, "Insufficient cores for speed testing") + + global P0, P2 + P0 = ports[0] + P2 = ports[2] + + pat = re.compile("P([0123])") + + # Prepare long prefix match table, replace P(x) port pattern + lpmStr_ipv4 = "static struct l3fwd_ipv4_route \ +l3fwd_ipv4_route_array[] = {\\\n" + rtLpmTbl = list(lpm_table_ipv4) + for idx in range(len(rtLpmTbl)): + rtLpmTbl[idx] = pat.sub(self.portRepl, rtLpmTbl[idx]) + lpmStr_ipv4 = lpmStr_ipv4 + ' ' * 4 + rtLpmTbl[idx] + ",\\\n" + lpmStr_ipv4 = lpmStr_ipv4 + "};" + print lpmStr_ipv4 + lpmStr_ipv6 = "static struct l3fwd_ipv6_route l3fwd_ipv6_route_array[] = {\\\n" + rtLpmTbl = list(lpm_table_ipv6) + for idx in range(len(rtLpmTbl)): + rtLpmTbl[idx] = pat.sub(self.portRepl, rtLpmTbl[idx]) + lpmStr_ipv6 = lpmStr_ipv6 + ' ' * 4 + rtLpmTbl[idx] + ",\\\n" + lpmStr_ipv6 = lpmStr_ipv6 + "};" + print lpmStr_ipv6 + self.dut.send_expect(r"sed -i '/l3fwd_ipv4_route_array\[\].*{/,/^\}\;/c\\%s' examples/ip_fragmentation/main.c" % lpmStr_ipv4, "# ") + self.dut.send_expect(r"sed -i '/l3fwd_ipv6_route_array\[\].*{/,/^\}\;/c\\%s' examples/ip_fragmentation/main.c" % lpmStr_ipv6, "# ") + # make application + out = self.dut.build_dpdk_apps("examples/ip_fragmentation") + self.verify("Error" not in out, "compilation error 1") + self.verify("No such file" not in out, "compilation error 2") + + def functional_check_ipv4(self, cores, pkt_sizes, burst=1, flag=None, funtion=None): + """ + Perform functional fragmentation checks. + """ + + coremask = dcts.create_mask(cores) + portmask = dcts.create_mask([P0, P2]) + numPortThread = len([P0, P2]) / len(cores) + result = True + errString = '' + + # run ipv4_frag + self.dut.send_expect("examples/ip_fragmentation/build/ip_fragmentation -c %s -n %d -- -p %s -q %s" % ( + coremask, self.dut.get_memory_channels(), portmask, numPortThread), "IP_FRAG:", 120) + + txItf = self.tester.get_interface(self.tester.get_local_port(P0)) + rxItf = self.tester.get_interface(self.tester.get_local_port(P2)) + dmac = self.dut.get_mac_address(P0) + for size in pkt_sizes[::burst]: + # simulate to set TG properties + if flag == 'frag': + # do fragment + expPkts = (1517 + size) / 1518 + val = 0 + else: + expPkts = 1 + val = 2 + + # set wait packet + self.tester.scapy_background() + self.tester.scapy_append('import string') + self.tester.scapy_append('p = sniff(iface="%s", count=%d)' % (rxItf, expPkts)) + self.tester.scapy_append('nr_packets=len(p)') + self.tester.scapy_append('reslist = [p[i].sprintf("%IP.len%;%IP.id%;%IP.flags%;%IP.frag%") for i in range(nr_packets)]') + self.tester.scapy_append('RESULT = string.join(reslist, ",")') + + # send packet + self.tester.scapy_foreground() + for times in range(burst): + self.tester.scapy_append('sendp([Ether(dst="%s")/IP(dst="100.10.0.1",src="1.2.3.4",flags=%d)/Raw(load="X"*%d)], iface="%s")' % (dmac, val, pkt_sizes[pkt_sizes.index(size) + times] - 38, txItf)) + + self.tester.scapy_execute() + out = self.tester.scapy_get_result() + nr_packets = len(out.split(',')) + if funtion is not None: + if not funtion(size, out.split(',')): + result = False + errString = "failed on fragment check size " + str(size) + break + elif nr_packets != expPkts: + result = False + errString = "Failed on forward packet size " + str(size) + break + + self.dut.send_expect("^C", "#") + # verify on the bottom so as to keep safety quit application + self.verify(result, errString) + + def functional_check_ipv6(self, cores, pkt_sizes, burst=1, flag=None, funtion=None): + """ + Perform functional fragmentation checks. + """ + coremask = dcts.create_mask(cores) + portmask = dcts.create_mask([P0, P2]) + numPortThread = len([P0, P2]) / len(cores) + result = True + errString = '' + + # run ipv4_frag + self.dut.send_expect("examples/ip_fragmentation/build/ip_fragmentation -c %s -n %d -- -p %s -q %s" % ( + coremask, self.dut.get_memory_channels(), portmask, numPortThread), "IP_FRAG:", 120) + + txItf = self.tester.get_interface(self.tester.get_local_port(P0)) + rxItf = self.tester.get_interface(self.tester.get_local_port(P2)) + dmac = self.dut.get_mac_address(P0) + for size in pkt_sizes[::burst]: + # simulate to set TG properties + if flag == 'frag': + # do fragment + expPkts = (1517 + size) / 1518 + val = 0 + else: + expPkts = 1 + val = 2 + + # set wait packet + self.tester.scapy_background() + self.tester.scapy_append('import string') + self.tester.scapy_append('p = sniff(iface="%s", count=%d)' % (rxItf, expPkts)) + self.tester.scapy_append('nr_packets=len(p)') + self.tester.scapy_append('reslist = [p[i].sprintf("%IPv6.plen%;%IPv6.id%;%IPv6ExtHdrFragment.m%;%IPv6ExtHdrFragment.offset%") for i in range(nr_packets)]') + self.tester.scapy_append('RESULT = string.join(reslist, ",")') + + # send packet + self.tester.scapy_foreground() + for times in range(burst): + self.tester.scapy_append('sendp([Ether(dst="%s")/IPv6(dst="101:101:101:101:101:101:101:101",src="ee80:ee80:ee80:ee80:ee80:ee80:ee80:ee80")/Raw(load="X"*%d)], iface="%s")' % (dmac, pkt_sizes[pkt_sizes.index(size) + times] - 58, txItf)) + + self.tester.scapy_execute() + out = self.tester.scapy_get_result() + nr_packets = len(out.split(',')) + if funtion is not None: + if not funtion(size, out.split(',')): + result = False + errString = "failed on fragment check size " + str(size) + break + elif nr_packets != expPkts: + result = False + errString = "Failed on forward packet size " + str(size) + break + + self.dut.send_expect("^C", "#") + # verify on the bottom so as to keep safety quit application + self.verify(result, errString) + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_ipfrag_normalfwd(self): + """ + Normal forward with 64, 128, 256, 512, 1024, 1518. + """ + + sizelist = [64, 128, 256, 512, 1024, 1518] + cores = self.dut.get_core_list("1S/1C/2T") + + self.functional_check_ipv4(cores, sizelist) + self.functional_check_ipv6(cores, sizelist) + + def test_ipfrag_nofragment(self): + """ + Don't fragment test with 1519 + """ + + sizelist = [1519, 1518] + cores = self.dut.get_core_list("1S/1C/2T") + self.tester.send_expect("ifconfig %s mtu 9200" % self.tester.get_interface(self.tester.get_local_port(P0)), "#") + self.tester.send_expect("ifconfig %s mtu 9200" % self.tester.get_interface(self.tester.get_local_port(P2)), "#") + + self.functional_check_ipv4(cores, sizelist, 2, 'nofrag') + self.functional_check_ipv6(cores, sizelist, 2, 'nofrag') + self.tester.send_expect("ifconfig %s mtu 1500" % self.tester.get_interface(self.tester.get_local_port(P0)), "#") + self.tester.send_expect("ifconfig %s mtu 1500" % self.tester.get_interface(self.tester.get_local_port(P2)), "#") + + def test_ipfrag_fragment(self): + """ + Fragment test with more than 1519 packet sizes. + """ + + sizelist = [1519, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000] + cores = self.dut.get_core_list("1S/1C/2T") + + self.tester.send_expect("ifconfig %s mtu 9200" % self.tester.get_interface(self.tester.get_local_port(P0)), "#") + self.tester.send_expect("ifconfig %s mtu 9200" % self.tester.get_interface(self.tester.get_local_port(P2)), "#") + + def chkfunc(size, output): + # check total size + if (1517 + size) / 1518 != len(output): + return False + + # check every field in packet + for pkt in output: + _, _, _, _ = pkt.split(';') + # length, ID, fragoff, flags + pass + return True + + self.functional_check_ipv4(cores, sizelist, 1, 'frag', chkfunc) + self.functional_check_ipv6(cores, sizelist, 1, 'frag', chkfunc) + self.tester.send_expect("ifconfig %s mtu 1500" % self.tester.get_interface(self.tester.get_local_port(P0)), "#") + self.tester.send_expect("ifconfig %s mtu 1500" % self.tester.get_interface(self.tester.get_local_port(P2)), "#") + + def benchmark(self, index, lcore, num_pthreads, size_list): + """ + Just Test IPv4 Throughput for selected parameters. + """ + + Bps = dict() + Pps = dict() + Pct = dict() + + if int(lcore[0]) == 1: + core_mask = dcts.create_mask(self.dut.get_core_list(lcore, socket=self.ports_socket)) + else: + core_mask = dcts.create_mask(self.dut.get_core_list(lcore)) + + portmask = dcts.create_mask([P0, P2]) + + self.dut.send_expect("examples/ip_fragmentation/build/ip_fragmentation -c %s -n %d -- -p %s -q %s" % ( + core_mask, self.dut.get_memory_channels(), portmask, num_pthreads), "IP_FRAG:", 120) + + result = [2, lcore, num_pthreads] + for size in size_list: + dmac = self.dut.get_mac_address(P0) + flows = ['Ether(dst="%s")/IP(src="1.2.3.4", dst="100.10.0.1", flags=0)/("X"*%d)' % (dmac, size - 38), + 'Ether(dst="%s")/IP(src="1.2.3.4", dst="100.20.0.1", flags=0)/("X"*%d)' % (dmac, size - 38), + 'Ether(dst="%s")/IPv6(dst="101:101:101:101:101:101:101:101",src="ee80:ee80:ee80:ee80:ee80:ee80:ee80:ee80")/Raw(load="X"*%d)' % (dmac, size - 58), + 'Ether(dst="%s")/IPv6(dst="201:101:101:101:101:101:101:101",src="ee80:ee80:ee80:ee80:ee80:ee80:ee80:ee80")/Raw(load="X"*%d)' % (dmac, size - 58)] + self.tester.scapy_append('wrpcap("test1.pcap", [%s])' % string.join(flows, ',')) + + # reserved for rx/tx bidirection test + dmac = self.dut.get_mac_address(P2) + flows = ['Ether(dst="%s")/IP(src="1.2.3.4", dst="100.30.0.1", flags=0)/("X"*%d)' % (dmac, size - 38), + 'Ether(dst="%s")/IP(src="1.2.3.4", dst="100.40.0.1", flags=0)/("X"*%d)' % (dmac, size - 38), + 'Ether(dst="%s")/IPv6(dst="301:101:101:101:101:101:101:101",src="ee80:ee80:ee80:ee80:ee80:ee80:ee80:ee80")/Raw(load="X"*%d)' % (dmac, size - 58), + 'Ether(dst="%s")/IPv6(dst="401:101:101:101:101:101:101:101",src="ee80:ee80:ee80:ee80:ee80:ee80:ee80:ee80")/Raw(load="X"*%d)' % (dmac, size - 58)] + self.tester.scapy_append('wrpcap("test2.pcap", [%s])' % string.join(flows, ',')) + + self.tester.scapy_execute() + + tgenInput = [] + tgenInput.append((self.tester.get_local_port(P0), self.tester.get_local_port(P2), "test1.pcap")) + tgenInput.append((self.tester.get_local_port(P2), self.tester.get_local_port(P0), "test2.pcap")) + + factor = (size + 1517) / 1518 + # wireSpd = 2 * 10000.0 / ((20 + size) * 8) + Bps[str(size)], Pps[str(size)] = self.tester.traffic_generator_throughput(tgenInput) + self.verify(Pps[str(size)] > 0, "No traffic detected") + Pps[str(size)] *= 1.0 / factor / 1000000 + Pct[str(size)] = (1.0 * Bps[str(size)] * 100) / (2 * 10000000000) + + result.append(Pps[str(size)]) + result.append(Pct[str(size)]) + + dcts.results_table_add_row(result) + + self.dut.send_expect("^C", "#") + + def test_perf_ipfrag_throughtput(self): + """ + Performance test for 64, 1518, 1519, 2k and 9k. + """ + + self.verify(self.nic == 'niantic', "throughtput case require niantic 10Gb self.nic") + self.tester.send_expect("ifconfig %s mtu 9600" % self.tester.get_interface(self.tester.get_local_port(P0)), "#") + self.tester.send_expect("ifconfig %s mtu 9600" % self.tester.get_interface(self.tester.get_local_port(P2)), "#") + + sizes = [64, 1518, 1519, 2000, 9000] + + tblheader = ["Ports", "S/C/T", "SW threads"] + for size in sizes: + tblheader.append("%dB Mpps" % size) + tblheader.append("%d" % size) + + dcts.results_table_add_header(tblheader) + + lcores = [("1S/1C/1T", 2), ("1S/1C/2T", 2), ("1S/2C/1T", 2), ("2S/1C/1T", 2)] + index = 1 + for (lcore, numThr) in lcores: + self.benchmark(index, lcore, numThr, sizes) + index += 1 + + dcts.results_table_print() + + self.tester.send_expect("ifconfig %s mtu 1500" % self.tester.get_interface(self.tester.get_local_port(P0)), "#") + self.tester.send_expect("ifconfig %s mtu 1500" % self.tester.get_interface(self.tester.get_local_port(P2)), "#") + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + self.dut.send_expect("^C", "#") + pass diff --git a/tests/TestSuite_jumboframes.py b/tests/TestSuite_jumboframes.py new file mode 100644 index 0000000..a563769 --- /dev/null +++ b/tests/TestSuite_jumboframes.py @@ -0,0 +1,226 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test the support of Jumbo Frames by Poll Mode Drivers + +""" + +import dcts +import re +from time import sleep + +from test_case import TestCase +from pmd_output import PmdOutput + +# +# +# Test class. +# + + +class TestJumboframes(TestCase): + # + # + # Utility methods and other non-test code. + # + + # Insert or move non-test functions here. + + def jumboframes_get_stat(self, portid, rx_tx): + """ + Get packets number from port statistic + """ + stats = self.pmdout.get_pmd_stats(portid) + if rx_tx == "rx": + return [stats['RX-packets'], stats['RX-errors'], stats['RX-bytes']] + elif rx_tx == "tx": + return [stats['TX-packets'], stats['TX-errors'], stats['TX-bytes']] + else: + return None + + def jumboframes_send_packet(self, pktsize, received=True): + """ + Send 1 packet to portid + """ + + gp0tx_pkts, _, gp0tx_bytes = [int(_) for _ in self.jumboframes_get_stat(self.dut_ports[0], "tx")] + gp1rx_pkts, gp1rx_err, gp1rx_bytes = [int(_) for _ in self.jumboframes_get_stat(self.dut_ports[1], "rx")] + + itf = self.tester.get_interface(self.tester.get_local_port(self.dut_ports[1])) + mac = self.dut.get_mac_address(self.dut_ports[1]) + + pktlen = pktsize - 18 + padding = pktlen - 20 + + self.tester.scapy_foreground() + self.tester.scapy_append('nutmac="%s"' % mac) + self.tester.scapy_append('sendp([Ether(dst=nutmac, src="52:00:00:00:00:00")/IP(len=%s)/Raw(load="\x50"*%s)], iface="%s")' % (pktlen, padding, itf)) + + out = self.tester.scapy_execute() + sleep(5) + + p0tx_pkts, _, p0tx_bytes = [int(_) for _ in self.jumboframes_get_stat(self.dut_ports[0], "tx")] + # p0tx_pkts, p0tx_err, p0tx_bytes + p1rx_pkts, p1rx_err, p1rx_bytes = [int(_) for _ in self.jumboframes_get_stat(self.dut_ports[1], "rx")] + + p0tx_pkts -= gp0tx_pkts + p0tx_bytes -= gp0tx_bytes + p1rx_pkts -= gp1rx_pkts + p1rx_bytes -= gp1rx_bytes + p1rx_err -= gp1rx_err + + if received: + self.verify(p0tx_pkts == p1rx_pkts and p0tx_bytes == pktsize and p1rx_bytes == pktsize, + "packet pass assert error") + + else: + self.verify(p0tx_pkts == p1rx_pkts and (p1rx_err == 1 or p1rx_pkts == 0), + "packet drop assert error") + + return out + + # + # + # + # Test cases. + # + def set_up_all(self): + """ + Run at the start of each test suite. + + + Dynamic config Prerequistites + """ + + self.dut_ports = self.dut.get_ports(self.nic) + self.verify(len(self.dut_ports) >= 2, "Insufficient ports") + + cores = self.dut.get_core_list('1S/2C/2T') + self.coremask = dcts.create_mask(cores) + + self.port_mask = dcts.create_mask([self.dut_ports[0], self.dut_ports[1]]) + + self.tester.send_expect("ifconfig %s mtu %s" % (self.tester.get_interface(self.tester.get_local_port(self.dut_ports[0])), 9200), "# ") + self.tester.send_expect("ifconfig %s mtu %s" % (self.tester.get_interface(self.tester.get_local_port(self.dut_ports[1])), 9200), "# ") + + self.pmdout = PmdOutput(self.dut) + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_jumboframes_normal_nojumbo(self): + """ + Dynamic config default mode test + """ + + self.dut.kill_all() + + cmd = r"./%s/build/app/test-pmd/testpmd -c%s -n 3 -- -i --rxd=1024 --txd=1024 \ + --burst=144 --txpt=32 --txht=0 --txfreet=0 --rxfreet=64 \ + --mbcache=200 --portmask=%s --mbuf-size=2048 --max-pkt-len=1518" % (self.target, self.coremask, self.port_mask) + + self.dut.send_expect(cmd, "testpmd> ", 120) + + self.dut.send_expect("start", "testpmd> ") + + self.jumboframes_send_packet(1517) + self.jumboframes_send_packet(1518) + + self.dut.send_expect("stop", "testpmd> ") + self.dut.send_expect("quit", "# ", 30) + + def test_jumboframes_jumbo_nojumbo(self): + """ + Dynamic config diable promiscuous test + """ + + self.dut.kill_all() + + cmd = r"./%s/build/app/test-pmd/testpmd -c%s -n 3 -- -i --rxd=1024 --txd=1024 \ + --burst=144 --txpt=32 --txht=8 --txwt=0 --txfreet=0 --rxfreet=64 \ + --mbcache=200 --portmask=%s --mbuf-size=2048 --max-pkt-len=1518" % (self.target, self.coremask, self.port_mask) + + self.dut.send_expect(cmd, "testpmd> ", 120) + self.dut.send_expect("start", "testpmd> ") + + self.jumboframes_send_packet(1519, False) + + self.dut.send_expect("stop", "testpmd> ") + self.dut.send_expect("quit", "# ", 30) + + def test_jumboframes_normal_jumbo(self): + """ + Dynamic config enable promiscuous test + """ + + self.dut.kill_all() + + cmd = r"./%s/build/app/test-pmd/testpmd -c%s -n 3 -- -i --rxd=1024 --txd=1024 \ + --burst=144 --txpt=32 --txht=8 --txwt=0 --txfreet=0 --rxfreet=64 \ + --mbcache=200 --portmask=%s --mbuf-size=2048 --max-pkt-len=%s" % (self.target, self.coremask, self.port_mask, 9000) + + self.dut.send_expect(cmd, "testpmd> ", 120) + self.dut.send_expect("start", "testpmd> ") + + self.jumboframes_send_packet(1517) + self.jumboframes_send_packet(1518) + + self.dut.send_expect("stop", "testpmd> ") + self.dut.send_expect("quit", "# ", 30) + + def test_jumboframes_jumbo_jumbo(self): + """ + Dynamic config enable promiscuous test + """ + + self.dut.kill_all() + + cmd = r"./%s/build/app/test-pmd/testpmd -c%s -n 3 -- -i --rxd=1024 --txd=1024 \ + --burst=144 --txpt=32 --txht=8 --txwt=0 --txfreet=0 --rxfreet=64 \ + --mbcache=200 --portmask=%s --mbuf-size=2048 --max-pkt-len=%s" % (self.target, self.coremask, self.port_mask, 9000) + + self.dut.send_expect(cmd, "testpmd> ", 120) + self.dut.send_expect("start", "testpmd> ") + + self.jumboframes_send_packet(1519) + self.jumboframes_send_packet(9000 - 1) + self.jumboframes_send_packet(9000) + + self.dut.send_expect("stop", "testpmd> ") + self.dut.send_expect("quit", "# ", 30) + + def test_jumboframes_bigger_jumbo(self): + """ + Dynamic config enable promiscuous test + """ + + self.dut.kill_all() + + cmd = r"./%s/build/app/test-pmd/testpmd -c%s -n 3 -- -i --rxd=1024 --txd=1024 \ + --burst=144 --txpt=32 --txht=8 --txwt=0 --txfreet=0 --rxfreet=64 \ + --mbcache=200 --portmask=%s --mbuf-size=2048 --max-pkt-len=%s" % ( + self.target, self.coremask, self.port_mask, 9000) + + self.dut.send_expect(cmd, "testpmd> ", 120) + self.dut.send_expect("start", "testpmd> ") + + self.jumboframes_send_packet(9000 + 1, False) + + self.dut.send_expect("quit", "# ", 30) + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + pass diff --git a/tests/TestSuite_l2fwd.py b/tests/TestSuite_l2fwd.py new file mode 100644 index 0000000..6233330 --- /dev/null +++ b/tests/TestSuite_l2fwd.py @@ -0,0 +1,215 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test Layer-2 Forwarding support + +""" + +import dcts +from test_case import TestCase +from plotting import Plotting +from settings import HEADER_SIZE + +# +# +# Test class. +# + + +class TestL2fwd(TestCase): + + # + # + # Utility methods and other non-test code. + # + + def plot_results(self): + + queues = [] + queues_results = [] + + for test_queues in self.test_queues: + queues.append(str(test_queues['queues'])) + results = [] + for frame_size in self.frame_sizes: + results.append(test_queues['pct'][frame_size]) + queues_results.append(results) + + image_path = self.plotting.create_bars_plot( + 'test_perf_l2fwd', + 'L2fwd, %d ports' % self.number_of_ports, + self.frame_sizes, + queues_results, + ylabel='% linerate', + legend=queues) + + dcts.results_plot_print(image_path) + + # + # + # + # Test cases. + # + def set_up_all(self): + """ + Run at the start of each test suite. + + L2fwd prerequisites. + """ + self.frame_sizes = [64, 65, 128, 256, 512, 1024, 1280, 1518] + + self.test_queues = [{'queues': 1, 'Mpps': {}, 'pct': {}}, + {'queues': 2, 'Mpps': {}, 'pct': {}}, + {'queues': 4, 'Mpps': {}, 'pct': {}}, + {'queues': 8, 'Mpps': {}, 'pct': {}} + ] + + self.core_config = "1S/4C/1T" + self.number_of_ports = 2 + self.headers_size = HEADER_SIZE['eth'] + HEADER_SIZE['ip'] + \ + HEADER_SIZE['udp'] + + self.dut_ports = self.dut.get_ports_performance(self.nic) + + self.verify(len(self.dut_ports) >= self.number_of_ports, + "Not enough ports for " + self.nic) + + self.ports_socket = self.dut.get_numa_id(self.dut_ports[0]) + + # compile + out = self.dut.build_dpdk_apps("./examples/l2fwd") + self.verify("Error" not in out, "Compilation error") + self.verify("No such" not in out, "Compilation error") + + self.table_header = ['Frame'] + for queue in self.test_queues: + self.table_header.append("%d queues Mpps" % queue['queues']) + self.table_header.append("% linerate") + + dcts.results_table_add_header(self.table_header) + self.plotting = Plotting(self.dut.crb['name'], self.target, self.nic) + + def set_up(self): + """ + Run before each test case. + """ + pass + + def quit_l2fwd(self): + self.dut.send_expect("fg", "l2fwd ", 5) + self.dut.send_expect("^C", "# ", 5) + + def test_port_testing(self): + """ + Check port forwarding. + """ + # the cases use the first two ports + port_mask = dcts.create_mask([self.dut_ports[0], self.dut_ports[1]]) + + self.dut.send_expect("./examples/l2fwd/build/app/l2fwd -n 1 -c f -- -q 8 -p %s &" % port_mask, "L2FWD: entering main loop", 60) + + for i in [0, 1]: + tx_port = self.tester.get_local_port(self.dut_ports[i]) + rx_port = self.tester.get_local_port(self.dut_ports[1 - i]) + + tx_interface = self.tester.get_interface(tx_port) + rx_interface = self.tester.get_interface(rx_port) + + self.tester.scapy_background() + self.tester.scapy_append('p = sniff(iface="%s", count=1)' % rx_interface) + self.tester.scapy_append('number_packets=len(p)') + self.tester.scapy_append('RESULT = str(number_packets)') + + self.tester.scapy_foreground() + self.tester.scapy_append('sendp([Ether()/IP()/UDP()/("X"*46)], iface="%s")' % tx_interface) + + self.tester.scapy_execute() + number_packets = self.tester.scapy_get_result() + self.verify(number_packets == "1", "Failed to switch L2 frame") + + self.quit_l2fwd() + + def test_perf_l2fwd_performance(self): + """ + Benchmark performance for frame_sizes. + """ + ports = [] + for port in xrange(self.number_of_ports): + ports.append(self.dut_ports[port]) + + port_mask = dcts.create_mask(ports) + core_mask = dcts.create_mask(self.dut.get_core_list(self.core_config, + socket=self.ports_socket)) + + for frame_size in self.frame_sizes: + + payload_size = frame_size - self.headers_size + + tgen_input = [] + for port in xrange(self.number_of_ports): + rx_port = self.tester.get_local_port(self.dut_ports[port % self.number_of_ports]) + tx_port = self.tester.get_local_port(self.dut_ports[(port + 1) % self.number_of_ports]) + destination_mac = self.dut.get_mac_address(self.dut_ports[(port + 1) % self.number_of_ports]) + self.tester.scapy_append('wrpcap("l2fwd_%d.pcap", [Ether(dst="%s")/IP()/UDP()/("X"*%d)])' % ( + port, destination_mac, payload_size)) + + tgen_input.append((tx_port, rx_port, "l2fwd_%d.pcap" % port)) + + self.tester.scapy_execute() + + for queues in self.test_queues: + + command_line = "./examples/l2fwd/build/app/l2fwd -n %d -c %s -- -q %s -p %s &" % \ + (self.dut.get_memory_channels(), core_mask, + str(queues['queues']), port_mask) + + self.dut.send_expect(command_line, "memory mapped", 60) + + info = "Executing l2fwd using %s queues, frame size %d and %s setup.\n" % \ + (queues['queues'], frame_size, self.core_config) + + self.logger.info(info) + dcts.report(info, annex=True) + dcts.report(command_line + "\n\n", frame=True, annex=True) + _, pps = self.tester.traffic_generator_throughput(tgen_input) + Mpps = pps / 1000000.0 + queues['Mpps'][frame_size] = Mpps + queues['pct'][frame_size] = Mpps * 100 / float(self.wirespeed( + self.nic, + frame_size, + self.number_of_ports)) + + self.quit_l2fwd() + + # Look for transmission error in the results + for frame_size in self.frame_sizes: + for n in range(len(self.test_queues)): + self.verify(self.test_queues[n]['Mpps'][frame_size] > 0, + "No traffic detected") + + # Prepare the results for table and plot printing + for frame_size in self.frame_sizes: + results_row = [] + results_row.append(frame_size) + for queue in self.test_queues: + results_row.append(queue['Mpps'][frame_size]) + results_row.append(queue['pct'][frame_size]) + + dcts.results_table_add_row(results_row) + + self.plot_results() + dcts.results_table_print() + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + pass diff --git a/tests/TestSuite_l3fwd.py b/tests/TestSuite_l3fwd.py new file mode 100644 index 0000000..2753631 --- /dev/null +++ b/tests/TestSuite_l3fwd.py @@ -0,0 +1,602 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + + +Layer-3 forwarding test script. +""" + +import dcts +import string +import re +from plotting import Plotting +from test_case import TestCase +from exception import VerifyFailure +from settings import HEADER_SIZE + + +# +# +# Test class. +# + + +class TestL3fwd(TestCase): + + path = "./examples/l3fwd/build/" + + test_cases_2_ports = {"1S/1C/1T": "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}), (P1,0,C{1.1.0})'", + "1S/1C/2T": "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}), (P1,0,C{1.1.1})'", + "1S/2C/1T": "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}), (P1,0,C{1.2.0})'" + } + + test_cases_4_ports = [(1, "1S/1C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P1,0,C{1.1.0}),(P2,0,C{1.1.0}),(P3,0,C{1.1.0})'"), + (1, "1S/1C/2T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P1,0,C{1.1.0}),(P2,0,C{1.1.1}),(P3,0,C{1.1.1})'"), + (1, "1S/2C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P1,0,C{1.1.0}),(P2,0,C{1.2.0}),(P3,0,C{1.2.0})'"), + (1, "1S/2C/2T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P1,0,C{1.1.1}),(P2,0,C{1.2.0}),(P3,0,C{1.2.1})'"), + (1, "1S/4C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P1,0,C{1.2.0}),(P2,0,C{1.3.0}),(P3,0,C{1.4.0})'"), + (1, "2S/1C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{0.1.0}),(P1,0,C{0.1.0}),(P2,0,C{1.1.0}),(P3,0,C{1.1.0})'"), + (1, "2S/1C/2T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{0.1.0}),(P1,0,C{0.1.1}),(P2,0,C{1.1.0}),(P3,0,C{1.1.1})'"), + (1, "2S/2C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{0.1.0}),(P1,0,C{0.2.0}),(P2,0,C{1.1.0}),(P3,0,C{1.2.0})'"), + (2, "1S/1C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P0,1,C{1.1.0}),(P1,0,C{1.1.0}),(P1,1,C{1.1.0}),(P2,0,C{1.1.0}),(P2,1,C{1.1.0}),(P3,0,C{1.1.0}),(P3,1,C{1.1.0})'"), + (2, "1S/1C/2T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P0,1,C{1.1.0}),(P1,0,C{1.1.0}),(P1,1,C{1.1.0}),(P2,0,C{1.1.1}),(P2,1,C{1.1.1}),(P3,0,C{1.1.1}),(P3,1,C{1.1.1})'"), + (2, "1S/2C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P0,1,C{1.1.0}),(P1,0,C{1.1.0}),(P1,1,C{1.1.0}),(P2,0,C{1.2.0}),(P2,1,C{1.2.0}),(P3,0,C{1.2.0}),(P3,1,C{1.2.0})'"), + (2, "1S/2C/2T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P0,1,C{1.1.0}),(P1,0,C{1.1.1}),(P1,1,C{1.1.1}),(P2,0,C{1.2.0}),(P2,1,C{1.2.0}),(P3,0,C{1.2.1}),(P3,1,C{1.2.1})'"), + (2, "1S/4C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P0,1,C{1.1.0}),(P1,0,C{1.2.0}),(P1,1,C{1.2.0}),(P2,0,C{1.3.0}),(P2,1,C{1.3.0}),(P3,0,C{1.4.0}),(P3,1,C{1.4.0})'"), + (2, "1S/4C/2T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{1.1.0}),(P0,1,C{1.1.1}),(P1,0,C{1.2.0}),(P1,1,C{1.2.1}),(P2,0,C{1.3.0}),(P2,1,C{1.3.1}),(P3,0,C{1.4.0}),(P3,1,C{1.4.1})'"), + (2, "2S/1C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{0.1.0}),(P0,1,C{0.1.0}),(P1,0,C{0.1.0}),(P1,1,C{0.1.0}),(P2,0,C{1.1.0}),(P2,1,C{1.1.0}),(P3,0,C{1.1.0}),(P3,1,C{1.1.0})'"), + (2, "2S/1C/2T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{0.1.0}),(P0,1,C{0.1.0}),(P1,0,C{0.1.1}),(P1,1,C{0.1.1}),(P2,0,C{1.1.0}),(P2,1,C{1.1.0}),(P3,0,C{1.1.1}),(P3,1,C{1.1.1})'"), + (2, "2S/2C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{0.1.0}),(P0,1,C{0.1.0}),(P1,0,C{0.2.0}),(P1,1,C{0.2.0}),(P2,0,C{1.1.0}),(P2,1,C{1.1.0}),(P3,0,C{1.2.0}),(P3,1,C{1.2.0})'"), + (2, "2S/2C/2T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{0.1.0}),(P0,1,C{0.1.1}),(P1,0,C{0.2.0}),(P1,1,C{0.2.1}),(P2,0,C{1.1.0}),(P2,1,C{1.1.1}),(P3,0,C{1.2.0}),(P3,1,C{1.2.1})'"), + (2, "2S/4C/1T", + "%s -c %s -n %d -- -p %s -P --config '(P0,0,C{0.1.0}),(P0,1,C{0.2.0}),(P1,0,C{0.3.0}),(P1,1,C{0.4.0}),(P2,0,C{1.1.0}),(P2,1,C{1.2.0}),(P3,0,C{1.3.0}),(P3,1,C{1.4.0})'") + ] + + queues_4_ports = [] + + for case in test_cases_4_ports: + if case[0] * 4 not in queues_4_ports: + queues_4_ports.append(case[0] * 4) + + host_table = [ + "{{IPv4(10,100,0,1), IPv4(1,2,3,4), 1, 10, IPPROTO_UDP}, P0}", + "{{IPv4(10,101,0,1), IPv4(1,2,3,4), 1, 10, IPPROTO_UDP}, P0}", + "{{IPv4(11,100,0,1), IPv4(1,2,3,4), 1, 11, IPPROTO_UDP}, P1}", + "{{IPv4(11,101,0,1), IPv4(1,2,3,4), 1, 11, IPPROTO_UDP}, P1}", + "{{IPv4(12,100,0,1), IPv4(1,2,3,4), 1, 12, IPPROTO_UDP}, P2}", + "{{IPv4(12,101,0,1), IPv4(1,2,3,4), 1, 12, IPPROTO_UDP}, P2}", + "{{IPv4(13,100,0,1), IPv4(1,2,3,4), 1, 13, IPPROTO_UDP}, P3}", + "{{IPv4(13,101,0,1), IPv4(1,2,3,4), 1, 13, IPPROTO_UDP}, P3}", + ] + + lpm_table = [ + "{IPv4(10,100,0,0), 24, P0}", + "{IPv4(10,101,0,0), 24, P0}", + "{IPv4(11,100,0,0), 24, P1}", + "{IPv4(11,101,0,0), 24, P1}", + "{IPv4(12,100,0,0), 24, P2}", + "{IPv4(12,101,0,0), 24, P2}", + "{IPv4(13,100,0,0), 24, P3}", + "{IPv4(13,101,0,0), 24, P3}", + ] + + frame_sizes = [64] # , 65, 128] + + methods = ['lpm', 'exact'] + + # + # + # Utility methods and other non-test code. + # + # Insert or move non-test functions here. + def portRepl(self, match): + """ + Function to replace P([0123]) pattern in tables + """ + + portid = match.group(1) + self.verify(int(portid) in range(4), "invalid port id") + if int(portid) >= len(valports): + return '0' + else: + return '%s' % valports[int(portid)] + + # + # + # + # Test cases. + # + + def plot_4_ports(self): + + data = self.l3fwd_test_results['data'] + + # Create a plot for each number of queues for frame size and mode comparison + cores = '1S/1C/1T' + for queues in TestL3fwd.queues_4_ports: + ydata = [] + lpm_ydata = [] + exact_ydata = [] + for frame_size in TestL3fwd.frame_sizes: + for row in data: + if row[1] * 4 == queues and row[2] == cores and \ + row[0] == frame_size: + if len(TestL3fwd.methods) == 2: + lpm_ydata.append(row[4]) + exact_ydata.append(row[6]) + else: + if 'lpm' in TestL3fwd.methods: + lpm_ydata.append(row[4]) + if 'exact' in TestL3fwd.methods: + exact_ydata.append(row[4]) + + if 'lpm' in TestL3fwd.methods: + ydata.append(lpm_ydata) + if 'exact' in TestL3fwd.methods: + ydata.append(exact_ydata) + + if len(ydata[0]) == 0: + self.logger.warning('No data for plotting 1S/1C/1T') + break + else: + try: + image_path = self.plotting.create_bars_plot( + 'test_perf_l3fwd_4ports_1S_1C_1T_%dRxQ' % queues, + 'LPM & Exact modes, 1S/1C/1T, %d Rx Queues, 4 ports' % queues, + TestL3fwd.frame_sizes, + ydata, + ylabel='% linerate', + legend=TestL3fwd.methods) + + dcts.results_plot_print(image_path, 50) + except VerifyFailure as e: + self.logger.error(str(e)) + + # Create a plot for each number of queues for core config and mode comparison + frame_size = TestL3fwd.frame_sizes[0] # Frame size fixed to the first selected + for queues in TestL3fwd.queues_4_ports: + + cores = [] + for row in data: + if row[2] not in cores and \ + row[1] * 4 == queues: + cores.append(row[2]) + + ydata = [] + lpm_ydata = [] + exact_ydata = [] + + for core in cores: + for row in data: + if row[1] * 4 == queues and \ + row[2] == core and \ + row[0] == frame_size: + if len(TestL3fwd.methods) == 2: + lpm_ydata.append(row[4]) + exact_ydata.append(row[6]) + else: + if 'lpm' in TestL3fwd.methods: + lpm_ydata.append(row[4]) + if 'exact' in TestL3fwd.methods: + exact_ydata.append(row[4]) + + if 'lpm' in TestL3fwd.methods: + ydata.append(lpm_ydata) + if 'exact' in TestL3fwd.methods: + ydata.append(exact_ydata) + + try: + image_path = self.plotting.create_bars_plot( + 'test_perf_l3fwd_4ports_%d_%dRxQ' % (frame_size, queues), + 'LPM & Exact modes, %dB, %d Rx Queues, 4 ports' % (frame_size, queues), + cores, + ydata, + ylabel='% linerate', + legend=TestL3fwd.methods) + + dcts.results_plot_print(image_path) + except VerifyFailure as e: + self.logger.error(str(e)) + + def plot_2_ports(self): + + data = self.l3fwd_test_results['data'] + + cores = [] + for row in data: + if row[2] not in cores: + cores.append(row[2]) + + # Create a plot for each mode for frame size and cores comparison + for mode in TestL3fwd.methods: + mode_ydata = [] + + for core in cores: + core_ydata = [] + for row in data: + if row[5] == mode and row[2] == core: + core_ydata.append(float(row[4])) + + mode_ydata.append(core_ydata) + + image_path = self.plotting.create_bars_plot( + 'test_perf_l3fwd_2ports_%s' % mode, + 'L3fwd %s mode, 2 ports' % mode, + TestL3fwd.frame_sizes, + mode_ydata, + ylabel='% linerate', + legend=cores) + + dcts.results_plot_print(image_path, 50) + + # If testing only one mode, do nothing else. + if len(TestL3fwd.methods) == 1: + return + + # Create a plot for 1st core config for mode and frame size comparison + core = '1S/1C/1T' + + ydata = [] + for mode in TestL3fwd.methods: + mode_ydata = [] + for frame_size in TestL3fwd.frame_sizes: + for row in data: + if row[2] == core and row[0] == frame_size and \ + row[5] == mode: + mode_ydata.append(float(row[4])) + + ydata.append(mode_ydata) + + str_frame_sizes = [] + for frame_size in TestL3fwd.frame_sizes: + str_frame_sizes.append(str(frame_size)) + + image_path = self.plotting.create_bars_plot( + 'test_perf_l3fwd_2ports_1S_1C_1T', + 'L3fwd 1S/1C/1T cores, 2 ports', + TestL3fwd.frame_sizes, + ydata, + ylabel='% linerate', + legend=TestL3fwd.methods) + + dcts.results_plot_print(image_path) + + def set_up_all(self): + """ + Run at the start of each test suite. + + + L3fwd Prerequisites + """ + # Based on h/w type, choose how many ports to use + ports = self.dut.get_ports(self.nic, socket=1) + if not ports: + ports = self.dut.get_ports(self.nic, socket=0) + + # Verify that enough ports are available + self.verify(len(ports) >= 2, "Insufficient ports for speed testing") + + # Verify that enough threads are available + cores = self.dut.get_core_list("2S/4C/2T") + self.verify(cores is not None, "Insufficient cores for speed testing") + + global valports + valports = [_ for _ in ports if self.tester.get_local_port(_) != -1] + self.verify(len(valports) >= 2, "Insufficient active ports for speed testing") + + pat = re.compile("P([0123])") + + # Prepare long prefix match table, replace P(x) port pattern + lpmStr = "static struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {\\\n" + for idx in range(len(TestL3fwd.lpm_table)): + TestL3fwd.lpm_table[idx] = pat.sub(self.portRepl, TestL3fwd.lpm_table[idx]) + lpmStr = lpmStr + ' ' * 4 + TestL3fwd.lpm_table[idx] + ",\\\n" + lpmStr = lpmStr + "};" + self.logger.debug(lpmStr) + + # Prepare host route table, replace P(x) port pattern + exactStr = "static struct ipv4_l3fwd_route ipv4_l3fwd_route_array[] = {\\\n" + for idx in range(len(TestL3fwd.host_table)): + TestL3fwd.host_table[idx] = pat.sub(self.portRepl, TestL3fwd.host_table[idx]) + exactStr = exactStr + ' ' * 4 + TestL3fwd.host_table[idx] + ",\\\n" + exactStr = exactStr + "};" + self.logger.debug(exactStr) + + # Compile l3fwd with LPM lookup. + self.dut.send_expect(r"sed -i '/ipv4_l3fwd_route_array\[\].*{/,/^\}\;/c\\%s' examples/l3fwd/main.c" % lpmStr, "# ") + out = self.dut.build_dpdk_apps("./examples/l3fwd", "USER_FLAGS=-DAPP_LOOKUP_METHOD=1") + self.verify("Error" not in out, "compilation error 1") + self.verify("No such file" not in out, "compilation error 2") + + # Backup the LPM exe and clean up the build. + self.dut.send_expect("mv -f examples/l3fwd/build/l3fwd examples/l3fwd/build/l3fwd_lpm", "# ") + out = self.dut.send_expect("make clean -C examples/l3fwd", "# ") + + # Compile l3fwd with hash/exact lookup. + self.dut.send_expect(r"sed -i -e '/ipv4_l3fwd_route_array\[\].*{/,/^\}\;/c\\%s' examples/l3fwd/main.c" % exactStr, "# ") + out = self.dut.build_dpdk_apps("./examples/l3fwd", "USER_FLAGS=-DAPP_LOOKUP_METHOD=0") + + self.verify("Error" not in out, "compilation error 1") + self.verify("No such file" not in out, "compilation error 2") + + # Backup the Hash/Exact exe. + self.dut.send_expect("mv -f examples/l3fwd/build/l3fwd examples/l3fwd/build/l3fwd_exact", "# ") + + self.l3fwd_test_results = {'header': [], + 'data': []} + + self.plotting = Plotting(self.dut.crb['name'], self.target, self.nic) + + def flows(self): + """ + Return a list of packets that implements the flows described in the + l3fwd test plan. + + """ + return [ + 'IP(src="1.2.3.4",dst="10.100.0.1")/UDP(sport=10,dport=1)', + 'IP(src="1.2.3.4",dst="10.101.0.1")/UDP(sport=10,dport=1)', + 'IP(src="1.2.3.4",dst="11.100.0.1")/UDP(sport=11,dport=1)', + 'IP(src="1.2.3.4",dst="11.101.0.1")/UDP(sport=11,dport=1)', + 'IP(src="1.2.3.4",dst="12.100.0.1")/UDP(sport=12,dport=1)', + 'IP(src="1.2.3.4",dst="12.101.0.1")/UDP(sport=12,dport=1)', + 'IP(src="1.2.3.4",dst="13.100.0.1")/UDP(sport=13,dport=1)', + 'IP(src="1.2.3.4",dst="13.101.0.1")/UDP(sport=13,dport=1)'] + + def repl(self, match): + pid = match.group(1) + qid = match.group(2) + self.logger.debug("%s\n" % match.group(3)) + lcid = self.dut.get_lcore_id(match.group(3)) + self.logger.debug("%s\n" % lcid) + + global corelist + corelist.append(int(lcid)) + + self.verify(int(pid) in range(4), "invalid port id") + self.verify(lcid, "invalid thread id") + + return '%s,%s,%s' % (str(valports[int(pid)]), qid, lcid) + + def get_throughput(self, frame_size, rx_queues_per_port, cores_config, command_line): + """ + Get the throughput for a test case from test_cases_4_ports. + """ + + output_pattern = re.compile("P([0123]),([0123]),(C\{\d.\d.\d\})") + + bps = dict() + pps = dict() + pct = dict() + + global corelist + corelist = [] + + while output_pattern.search(command_line): + command_line = output_pattern.sub(self.repl, command_line) + + self.logger.debug("%s\n" % str(corelist)) + core_mask = dcts.create_mask(set(corelist)) + + # First, measure by two different methods + for method in TestL3fwd.methods: + # start l3fwd + method_command_line = command_line % (TestL3fwd.path + "l3fwd_" + method, + core_mask, + self.dut.get_memory_channels(), + dcts.create_mask(valports[:4])) + + dcts.report(method_command_line + "\n", frame=True, annex=True) + + out = self.dut.send_expect(method_command_line, "L3FWD:", 120) + + # measure test + tgen_input = [] + for rxPort in range(4): + if rxPort % 2 == 0: + tx_interface = self.tester.get_local_port(valports[rxPort + 1]) + else: + tx_interface = self.tester.get_local_port(valports[rxPort - 1]) + + rx_interface = self.tester.get_local_port(valports[rxPort]) + tgen_input.append((tx_interface, rx_interface, "dst%d.pcap" % valports[rxPort])) + + # FIX ME + bps[method], pps[method] = self.tester.traffic_generator_throughput(tgen_input) + self.verify(pps[method] > 0, "No traffic detected") + pps[method] /= 1000000.0 + pct[method] = pps[method] * 100 / float(self.wirespeed(self.nic, + frame_size, + 4)) + + # stop l3fwd + self.dut.send_expect("^C", "#") + + data_row = [frame_size, rx_queues_per_port, cores_config] + for method in TestL3fwd.methods: + data_row.append(pps[method]) + data_row.append(pct[method]) + + # generate report table + dcts.results_table_add_row(data_row) + self.l3fwd_test_results['data'].append(data_row) + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_perf_l3fwd_4ports(self): + """ + L3fwd main 4 ports. + """ + + # Based on h/w type, choose how many ports to use + ports = self.dut.get_ports(self.nic) + # Verify that enough ports are available + self.verify(len(ports) >= 4, "Insufficient ports for speed testing") + + header_row = ["Frame size", "RX Queues/NIC Port", "S/C/T"] + + for method in TestL3fwd.methods: + header_row.append('%s Mpps' % method) + header_row.append('% linerate') + + dcts.results_table_add_header(header_row) + self.l3fwd_test_results['header'] = header_row + self.l3fwd_test_results['data'] = [] + + for frame_size in TestL3fwd.frame_sizes: + + # Prepare traffic flow + payload_size = frame_size - HEADER_SIZE['udp'] - \ + HEADER_SIZE['ip'] - HEADER_SIZE['eth'] + + for _port in range(4): + dmac = self.dut.get_mac_address(valports[_port]) + flows = ['Ether(dst="%s")/%s/("X"*%d)' % (dmac, flow, payload_size) for flow in self.flows()[_port * 2:(_port + 1) * 2]] + self.tester.scapy_append('wrpcap("dst%d.pcap", [%s])' % (valports[_port], string.join(flows, ','))) + + self.tester.scapy_execute() + + dcts.report("Flows for 4 ports, %d frame size.\n" % (frame_size), + annex=True) + dcts.report("%s" % string.join(flows, '\n'), + frame=True, annex=True) + + # Get the number of sockets of the board + number_sockets = self.dut.send_expect("grep \"processor\|physical id\|core id\|^$\" /proc/cpuinfo | grep physical | sort -u | wc -l", "# ") + number_sockets = int(number_sockets.split('\r\n')[0]) + + # Run case by case + for test_case in TestL3fwd.test_cases_4_ports: + + # Check if the board has sockets enough for the test case + if number_sockets >= int(test_case[1].split('/')[0][0]): + self.get_throughput(frame_size, *test_case) + + self.plot_4_ports() + dcts.results_table_print() + + def test_perf_l3fwd_2ports(self): + """ + L3fwd main 2 ports. + """ + + header_row = ["Frame", "Ports", "S/C/T", "Mpps", "% linerate", "mode"] + self.l3fwd_test_results['header'] = header_row + dcts.results_table_add_header(header_row) + self.l3fwd_test_results['data'] = [] + + for frame_size in TestL3fwd.frame_sizes: + + # Prepare traffic flow + payload_size = frame_size - HEADER_SIZE['udp'] - \ + HEADER_SIZE['ip'] - HEADER_SIZE['eth'] + + flows = ['Ether()/%s/("X"*%d)' % (flow, payload_size) for flow in self.flows()[:4]] + + dcts.report("Flows for 2 ports, %d frame size.\n" % (frame_size), + annex=True) + dcts.report("%s" % string.join(flows, '\n'), + frame=True, annex=True) + + self.tester.scapy_append('wrpcap("test2ports.pcap", [%s])' % string.join(flows, ',')) + self.tester.scapy_execute() + + # Prepare the command line + global corelist + pat = re.compile("P([0123]),([0123]),(C\{\d.\d.\d\})") + coreMask = {} + rtCmdLines = dict(TestL3fwd.test_cases_2_ports) + for key in rtCmdLines.keys(): + corelist = [] + while pat.search(rtCmdLines[key]): + rtCmdLines[key] = pat.sub(self.repl, rtCmdLines[key]) + self.logger.info("%s\n" % str(corelist)) + coreMask[key] = dcts.create_mask(set(corelist)) + + # measure by two different mode + for mode in TestL3fwd.methods: + + # start l3fwd + index = 0 + subtitle = [] + for cores in rtCmdLines.keys(): + + info = "Executing l3fwd using %s mode, 2 ports, %s and %d frame size.\n" % ( + mode, cores, frame_size) + + self.logger.info(info) + dcts.report(info, annex=True) + + subtitle.append(cores) + cmdline = rtCmdLines[cores] % (TestL3fwd.path + "l3fwd_" + mode, coreMask[cores], + self.dut.get_memory_channels(), dcts.create_mask(valports[:2])) + + dcts.report(cmdline + "\n", frame=True, annex=True) + + out = self.dut.send_expect(cmdline, "L3FWD:", 120) + + # Measure test + tgenInput = [] + for rxPort in range(2): + # No use on rx/tx limitation + if rxPort % 2 == 0: + txIntf = self.tester.get_local_port(valports[rxPort + 1]) + else: + txIntf = self.tester.get_local_port(valports[rxPort - 1]) + + rxIntf = self.tester.get_local_port(valports[rxPort]) + + tgenInput.append((txIntf, rxIntf, "test2ports.pcap")) + + _, pps = self.tester.traffic_generator_throughput(tgenInput) + self.verify(pps > 0, "No traffic detected") + pps /= 1000000.0 + linerate = self.wirespeed(self.nic, frame_size, 2) + pct = pps * 100 / linerate + + index += 1 + + # Stop l3fwd + self.dut.send_expect("^C", "#") + + data_row = [frame_size, 2, cores, str(pps), str(pct), mode] + dcts.results_table_add_row(data_row) + self.l3fwd_test_results['data'].append(data_row) + + self.plot_2_ports() + dcts.results_table_print() + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + pass diff --git a/tests/TestSuite_link_flowctrl.py b/tests/TestSuite_link_flowctrl.py new file mode 100644 index 0000000..98ff84b --- /dev/null +++ b/tests/TestSuite_link_flowctrl.py @@ -0,0 +1,407 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test for Ethernet Link Flow Control Features by Poll Mode Drivers + +""" + +import dcts +import re + +from time import sleep +from test_case import TestCase + +# +# +# Test class. +# + + +class TestLinkFlowctrl(TestCase): + + # + # + # + # Test cases. + # + pause_frame_dst = "01:80:C2:00:00:01" + pause_frame_type = "0x8808" + pause_frame_opcode = "\\x00\\x01" + pause_frame_control = "\\x00\\xFF" + pause_frame_paddign = "\\x00" * 42 + + pause_frame = '[Ether(src="%s",dst="%s",type=%s)/("%s%s%s")]' + + frames_to_sent = 10 + + packet_size = 66 # 66 allows frame loss + ip_header_size = 20 + udp_header_size = 8 + eth_header_size = 18 + payload_size = packet_size - eth_header_size - ip_header_size - udp_header_size + + def set_up_all(self): + """ + Run at the start of each test suite. + + Link flow control Prerequisites + """ + + self.dutPorts = self.dut.get_ports(self.nic) + self.verify(len(self.dutPorts) > 1, "Insuficient ports") + + self.rx_port = self.dutPorts[0] + self.tester_tx_mac = self.tester.get_mac(self.tester.get_local_port(self.rx_port)) + + self.tx_port = self.dutPorts[1] + + self.portMask = dcts.create_mask([self.rx_port, self.tx_port]) + self.memChannels = self.dut.get_memory_channels() + + cmdline = "./%s/app/testpmd -c ffffff -n %s -- -i --burst=1" % (self.target, self.memChannels) + \ + "--txpt=32 --txht=8 --txwt=0 --txfreet=0 --mbcache=250 --portmask=%s" % self.portMask + + self.dut.send_expect(cmdline, "testpmd> ", 120) + + def pause_frame_loss_test(self, rx_flow_control='off', + tx_flow_control='off', + pause_frame_fwd='off'): + + tester_tx_port = self.tester.get_local_port(self.rx_port) + tester_rx_port = self.tester.get_local_port(self.tx_port) + + tgenInput = [] + tgenInput.append((tester_tx_port, tester_rx_port, "test.pcap")) + + self.dut.send_expect("set flow_ctrl rx %s tx %s 300 50 10 1 mac_ctrl_frame_fwd %s autoneg on %d " % ( + rx_flow_control, + tx_flow_control, + pause_frame_fwd, + self.rx_port), + "testpmd> ") + + self.dut.send_expect("set fwd csum", "testpmd> ") + self.dut.send_expect("start", "testpmd> ") + + self.tester.scapy_append('wrpcap("test.pcap",[Ether()/IP()/UDP()/("X"*%d)])' % + TestLinkFlowctrl.payload_size) + + self.tester.scapy_execute() + + # Run traffic generator + result = self.tester.traffic_generator_loss(tgenInput, 100) + self.dut.send_expect("stop", "testpmd> ") + + return result + + def get_testpmd_port_stats(self, ports): + """ + Returns the number of packets transmitted and received from testpmd. + Uses testpmd show port stats. + """ + + rx_pattern = "RX-packets: (\d*)" + tx_pattern = "TX-packets: (\d*)" + rx = re.compile(rx_pattern) + tx = re.compile(tx_pattern) + + port_stats = {} + + for port in ports: + out = self.dut.send_expect("show port stats %d" % port, + "testpmd> ") + + rx_packets = int(rx.search(out).group(1)) + tx_packets = int(tx.search(out).group(1)) + + port_stats[port] = (rx_packets, tx_packets) + + return port_stats + + def pause_frame_test(self, frame, flow_control='off', + pause_frame_fwd='off'): + """ + Sets testpmd flow control and mac ctrl frame fwd according to the + parameters, starts forwarding and clears the stats, then sends the + passed frame and stops forwarding. + Returns the testpmd port stats. + """ + + tester_tx_port = self.tester.get_local_port(self.rx_port) + tx_interface = self.tester.get_interface(tester_tx_port) + tester_rx_port = self.tester.get_local_port(self.tx_port) + + tgenInput = [] + tgenInput.append((tester_tx_port, tester_rx_port, "test.pcap")) + + self.dut.send_expect("set flow_ctrl rx %s tx %s 300 50 10 1 mac_ctrl_frame_fwd %s autoneg on %d " % ( + flow_control, + flow_control, + pause_frame_fwd, + self.rx_port), + "testpmd> ") + + self.dut.send_expect("set fwd io", "testpmd> ") + self.dut.send_expect("start", "testpmd> ") + self.dut.send_expect("clear port stats all", "testpmd> ") + + self.tester.scapy_foreground() + self.tester.scapy_append('sendp(%s, iface="%s", count=%d)' % (frame, + tx_interface, + TestLinkFlowctrl.frames_to_sent)) + + self.tester.scapy_execute() + + # The following sleep is needed to allow all the packets to arrive. + # 1s works for Crown Pass (FC18) DUT, Lizard Head Pass (FC14) tester + # using Niantic. Increase it in case of packet loosing. + sleep(1) + + self.dut.send_expect("stop", "testpmd> ") + + port_stats = self.get_testpmd_port_stats((self.rx_port, self.tx_port)) + + return port_stats + + def check_pause_frame_test_result(self, result, expected_rx=False, expected_fwd=False): + """ + Verifies the test results (use pause_frame_test before) against + the expected behavior. + """ + print "Result (port, rx, tx) %s, expected rx %s, expected fwd %s" % (result, + expected_rx, + expected_fwd) + + if expected_rx: + self.verify(result[self.rx_port][0] == TestLinkFlowctrl.frames_to_sent, + "Pause Frames are not being received by testpmd (%d received)" % + result[self.rx_port][0]) + if expected_fwd: + self.verify(result[self.tx_port][1] == TestLinkFlowctrl.frames_to_sent, + "Pause Frames are not being forwarded by testpmd (%d sent)" % ( + result[self.tx_port][1])) + else: + self.verify(result[self.tx_port][1] == 0, + "Pause Frames are being forwarded by testpmd (%d sent)" % ( + result[self.tx_port][1])) + else: + self.verify(result[self.rx_port][0] == 0, + "Pause Frames are being received by testpmd (%d received)" % + result[self.rx_port][0]) + + def build_pause_frame(self, option=0): + """ + Build the PAUSE Frame for the tests. 3 available options: + 0: Correct frame (correct src and dst addresses and opcode) + 1: Wrong source frame (worng src, correct and dst address and opcode) + 2: Wrong opcode frame (correct src and dst address and wrong opcode) + 3: Wrong destination frame (correct src and opcode, wrong dst address) + """ + + if option == 1: + return TestLinkFlowctrl.pause_frame % ("00:01:02:03:04:05", + TestLinkFlowctrl.pause_frame_dst, + TestLinkFlowctrl.pause_frame_type, + TestLinkFlowctrl.pause_frame_opcode, + TestLinkFlowctrl.pause_frame_control, + TestLinkFlowctrl.pause_frame_paddign) + + elif option == 2: + return TestLinkFlowctrl.pause_frame % (self.tester_tx_mac, + TestLinkFlowctrl.pause_frame_dst, + TestLinkFlowctrl.pause_frame_type, + "\\x00\\x02", + TestLinkFlowctrl.pause_frame_control, + TestLinkFlowctrl.pause_frame_paddign) + elif option == 3: + return TestLinkFlowctrl.pause_frame % (self.tester_tx_mac, + "01:80:C2:00:AB:10", + TestLinkFlowctrl.pause_frame_type, + TestLinkFlowctrl.pause_frame_opcode, + TestLinkFlowctrl.pause_frame_control, + TestLinkFlowctrl.pause_frame_paddign) + + return TestLinkFlowctrl.pause_frame % (self.tester_tx_mac, + TestLinkFlowctrl.pause_frame_dst, + TestLinkFlowctrl.pause_frame_type, + TestLinkFlowctrl.pause_frame_opcode, + TestLinkFlowctrl.pause_frame_control, + TestLinkFlowctrl.pause_frame_paddign) + + def test_flowctrl_off_pause_fwd_off(self): + """ + Flow control disabled, MAC PAUSE frame forwarding disabled. + PAUSE Frames must not be received by testpmd + """ + + pause_frames = [self.build_pause_frame(0), + self.build_pause_frame(1), + self.build_pause_frame(2), + self.build_pause_frame(3)] + + for frame in pause_frames: + port_stats = self.pause_frame_test(frame) + self.check_pause_frame_test_result(port_stats) + + def test_flowctrl_on_pause_fwd_off(self): + """ + Flow control enabled, MAC PAUSE frame forwarding disabled. + PAUSE Frames must not be received by testpmd + """ + + pause_frames = [self.build_pause_frame(0), + self.build_pause_frame(1), + self.build_pause_frame(2), + self.build_pause_frame(3)] + + for frame in pause_frames: + port_stats = self.pause_frame_test(frame, flow_control='on') + self.check_pause_frame_test_result(port_stats) + + def test_flowctrl_off_pause_fwd_on(self): + """ + Flow control disabled, MAC PAUSE frame forwarding enabled. + All PAUSE Frames must be forwarded by testpmd. + """ + + # Regular frames, check for no frames received + pause_frame = self.build_pause_frame() + port_stats = self.pause_frame_test(pause_frame, pause_frame_fwd='on') + self.check_pause_frame_test_result(port_stats, True, True) + + # Wrong src MAC, check for no frames received + pause_frame = self.build_pause_frame(1) + port_stats = self.pause_frame_test(pause_frame, pause_frame_fwd='on') + self.check_pause_frame_test_result(port_stats, True, True) + + # Unrecognized frames (wrong opcode), check for all frames received and fwd + pause_frame = self.build_pause_frame(2) + port_stats = self.pause_frame_test(pause_frame, pause_frame_fwd='on') + self.check_pause_frame_test_result(port_stats, True, True) + + # Wrong dst MAC, check for all frames received + pause_frame = self.build_pause_frame(3) + port_stats = self.pause_frame_test(pause_frame, pause_frame_fwd='on') + self.check_pause_frame_test_result(port_stats, True, True) + + def test_flowctrl_on_pause_fwd_on(self): + """ + Flow control enabled, MAC PAUSE frame forwarding enabled. + Only unrecognized PAUSE Frames must be forwarded by testpmd. + """ + + # Regular frames, check for no frames received + pause_frame = self.build_pause_frame() + port_stats = self.pause_frame_test(pause_frame, flow_control='on', + pause_frame_fwd='on') + self.check_pause_frame_test_result(port_stats) + + # Wrong src MAC, check for no frames received + pause_frame = self.build_pause_frame(1) + port_stats = self.pause_frame_test(pause_frame, flow_control='on', + pause_frame_fwd='on') + self.check_pause_frame_test_result(port_stats) + + # Unrecognized frames (wrong opcode), check for all frames received and fwd + pause_frame = self.build_pause_frame(2) + port_stats = self.pause_frame_test(pause_frame, flow_control='on', + pause_frame_fwd='on') + self.check_pause_frame_test_result(port_stats, True, True) + + # Wrong dst MAC, check for all frames received + pause_frame = self.build_pause_frame(3) + port_stats = self.pause_frame_test(pause_frame, flow_control='on', + pause_frame_fwd='on') + self.check_pause_frame_test_result(port_stats, True, True) + + def test_perf_flowctrl_on_pause_fwd_on(self): + """ + Disable link flow control and PAUSE frame forwarding + """ + + result = self.pause_frame_loss_test(rx_flow_control='on', + tx_flow_control='on', + pause_frame_fwd='on') + + print "Packet loss: %.3f%%" % result + + self.verify(result <= 0.01, + "Link flow control fail, the loss percent is more than 1%") + + def test_perf_flowctrl_on_pause_fwd_off(self): + """ + Disable link flow control and enable PAUSE frame forwarding + """ + + result = self.pause_frame_loss_test(rx_flow_control='on', + tx_flow_control='on', + pause_frame_fwd='off') + + print "Packet loss: %.3f%%" % result + + self.verify(result <= 0.01, + "Link flow control fail, the loss percent is more than 1%") + + def test_perf_flowctrl_rx_on(self): + """ + Enable only rx link flow control + """ + + result = self.pause_frame_loss_test(rx_flow_control='on', + tx_flow_control='on', + pause_frame_fwd='off') + + print "Packet loss: %.3f%%" % result + + self.verify(result <= 0.01, + "Link flow control fail, the loss percent is more than 1%") + + def test_perf_flowctrl_off_pause_fwd_on(self): + """ + Enable link flow control and disable PAUSE frame forwarding + """ + + result = self.pause_frame_loss_test(rx_flow_control='off', + tx_flow_control='off', + pause_frame_fwd='on') + + print "Packet loss: %.3f%%" % result + + self.verify(result >= 0.5, + "Link flow control fail, the loss percent is less than 50%") + + def test_perf_flowctrl_off_pause_fwd_off(self): + """ + Disable link flow control and PAUSE frame forwarding + """ + + result = self.pause_frame_loss_test(rx_flow_control='off', + tx_flow_control='off', + pause_frame_fwd='off') + + print "Packet loss: %.3f%%" % result + + self.verify(result >= 0.5, + "Link flow control fail, the loss percent is less than 50%") + + def test_perf_flowctrl_tx_on(self): + """ + Disable link flow control and PAUSE frame forwarding + """ + + result = self.pause_frame_loss_test(rx_flow_control='off', + tx_flow_control='on', + pause_frame_fwd='off') + + print "Packet loss: %.3f%%" % result + + self.verify(result <= 0.01, + "Link flow control fail, the loss percent is more than 1%") + + def tear_down_all(self): + """ + Run after each test case. + """ + self.dut.send_expect("quit", "# ") diff --git a/tests/TestSuite_multiprocess.py b/tests/TestSuite_multiprocess.py new file mode 100644 index 0000000..3fbc31e --- /dev/null +++ b/tests/TestSuite_multiprocess.py @@ -0,0 +1,258 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Multi-process Test. + +""" + +import dcts +import time +from etgen import IxiaPacketGenerator + +executions = [] +from test_case import TestCase + +# +# +# Test class. +# + + +class TestMultiprocess(TestCase, IxiaPacketGenerator): + + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + Run at the start of each test suite. + + Multiprocess prerequisites. + Requirements: + OS is not freeBSD + DUT core number >= 4 + multi_process build pass + """ + self.verify('bsdapp' not in self.target, "Multiprocess not support freebsd") + + self.verify(len(self.dut.get_all_cores()) >= 4, "Not enough Cores") + self.tester.extend_external_packet_generator(TestMultiprocess, self) + + out = self.dut.build_dpdk_apps("./examples/multi_process/") + self.verify('Error' not in out, "Compilation failed") + + executions.append({'nprocs': 1, 'cores': '1S/1C/1T', 'pps': 0}) + executions.append({'nprocs': 2, 'cores': '1S/1C/2T', 'pps': 0}) + executions.append({'nprocs': 2, 'cores': '1S/2C/1T', 'pps': 0}) + executions.append({'nprocs': 4, 'cores': '1S/2C/2T', 'pps': 0}) + executions.append({'nprocs': 4, 'cores': '1S/4C/1T', 'pps': 0}) + executions.append({'nprocs': 8, 'cores': '1S/4C/2T', 'pps': 0}) + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_multiprocess_simple_mpbasicoperation(self): + """ + Basic operation. + """ + + # Send message from secondary to primary + self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c 3 --proc-type=primary > out &" % self.target, "# ", 10) + time.sleep(20) + self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c C --proc-type=secondary" % self.target, "Finished Process Init", 10) + + self.dut.send_expect("send hello_primary", ">") + self.dut.send_expect("quit", "# ") + self.dut.send_expect("fg", "simple_mp") + self.dut.send_expect("quit", "# ") + out = self.dut.send_expect("cat out", "# ") + + self.verify("Received 'hello_primary'" in out, "Message not received on primary process") + + # Send message from primary to secondary + self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c 3 --proc-type=primary &" % self.target, "# ", 10) + time.sleep(20) + self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c C --proc-type=secondary > out &" % self.target, "Finished Process Init", 10) + self.dut.send_expect("fg 1", "simple_mp") + self.dut.send_expect("send hello_secondary", ">") + self.dut.send_expect("quit", "# ") + self.dut.send_expect("fg 2", "simple_mp") + self.dut.send_expect("quit", "# ") + out = self.dut.send_expect("cat out", "# ") + + self.verify("Received 'hello_secondary'" in out, + "Message not received on primary process") + + def test_multiprocess_simple_mploadtest(self): + """ + Load test of Simple MP application. + """ + + self.dut.kill_all() + self.dut.send_expect("fg", "# ") + + self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c 3 --proc-type=primary > testing.txt &" % self.target, "# ") + time.sleep(20) + self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c C --proc-type=secondary" % self.target, "Finished Process Init", 10) + stringsSent = 0 + for line in open('/usr/share/dict/words', 'r').readlines(): + line = line.split('\n')[0] + self.dut.send_expect("send %s" % line, ">") + stringsSent += 1 + if stringsSent == 3: + break + + time.sleep(5) + self.dut.send_expect("quit", "# ") + self.dut.send_expect("fg", ">") + + def test_multiprocess_simple_mpapplicationstartup(self): + """ + Test use of Auto for Application Startup. + """ + + self.dut.kill_all() + + # Send message from secondary to primary (auto process type) + self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c 3 --proc-type=auto > out &" % self.target, "# ", 30) + time.sleep(20) + out = self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c C --proc-type=auto" % self.target, "Finished Process Init", 30) + self.verify("EAL: Auto-detected process type: SECONDARY" in out, + "The type of process (SECONDARY) was not detected properly") + + self.dut.send_expect("send hello_primary", ">") + self.dut.send_expect("quit", "# ") + self.dut.send_expect("fg", "simple_mp") + self.dut.send_expect("quit", "# ") + out = self.dut.send_expect("cat out", "# ") + + self.verify("EAL: Auto-detected process type: PRIMARY" in out, "The type of process (PRIMARY) was not detected properly") + self.verify("Received 'hello_primary'" in out, "Message not received on primary process") + + # Send message from primary to secondary (auto process type) + out = self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c 3 --proc-type=auto > out_primary &" % self.target, "# ", 30) + time.sleep(20) + self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c C --proc-type=auto > out_secondary &" % self.target, "#", 30) + self.dut.send_expect("fg 1", "simple_mp") + self.dut.send_expect("send hello_secondary", ">") + self.dut.send_expect("quit", "# ") + self.dut.send_expect("fg 2", "simple_mp") + self.dut.send_expect("quit", "# ") + out = self.dut.send_expect("cat out_primary", "# ") + self.verify("EAL: Auto-detected process type: PRIMARY" in out, "The type of process (PRIMARY) was not detected properly") + + out = self.dut.send_expect("cat out_secondary", "# ") + self.verify("EAL: Auto-detected process type: SECONDARY" in out, "The type of process (SECONDARY) was not detected properly") + self.verify("Received 'hello_secondary'" in out, + "Message not received on primary process") + + def test_multiprocess_simple_mpnoflag(self): + """ + Multiple processes without "--proc-type" flag. + """ + + self.dut.kill_all() + + self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c 3 -m 64 &" % self.target, "Finished Process Init") + out = self.dut.send_expect("./examples/multi_process/simple_mp/simple_mp/%s/simple_mp -n 1 -c C" % self.target, "# ") + self.verify("Is another primary process running" in out, + "No other primary process detected") + + self.dut.send_expect("fg", " > ") + self.dut.send_expect("quit", "# ") + + def test_perf_multiprocess_client_serverperformance(self): + """ + Benchmark Multiprocess client-server performance. + """ + self.dut.kill_all() + self.dut.send_expect("fg", "# ") + dutPorts = self.dut.get_ports(self.nic) + txPort = self.tester.get_local_port(dutPorts[0]) + rxPort = self.tester.get_local_port(dutPorts[1]) + mac = self.tester.get_mac(txPort) + + self.tester.scapy_append('dmac="%s"' % self.dut.get_mac_address(dutPorts[0])) + self.tester.scapy_append('smac="%s"' % mac) + if not self.dut.want_perf_tests: + self.tester.scapy_append('flows = [Ether(src=smac, dst=dmac)/IP(src="192.168.1.%s" % src, dst="192.168.1.%s" % dst)/("X"*26) for src in range(64) for dst in range(64)]') + else: + self.tester.scapy_append('flows = [Ether(src=smac, dst=dmac)/IP(src="192.168.1.1", dst="192.168.1.1")/("X"*26)]') + self.tester.scapy_append('wrpcap("test.pcap", flows)') + self.tester.scapy_execute() + + validExecutions = [] + for execution in executions: + if len(self.dut.get_core_list(execution['cores'])) == execution['nprocs']: + validExecutions.append(execution) + + for execution in validExecutions: + coreList = self.dut.get_core_list(execution['cores']) + + coreMask = dcts.create_mask(self.dut.get_core_list('1S/1C/1T')) + portMask = dcts.create_mask([dutPorts[0], dutPorts[1]]) + self.dut.send_expect("./examples/multi_process/client_server_mp/mp_server/client_server_mp/mp_server/%s/mp_server -n %d -c %s -- -p %s -n %d" % (self.target, self.dut.get_memory_channels(), "0xA0", portMask, execution['nprocs']), "Finished Process Init", 20) + self.dut.send_expect("^Z", "\r\n") + self.dut.send_expect("bg", "# ") + + for n in range(execution['nprocs']): + time.sleep(5) + coreMask = dcts.create_mask([coreList[n]]) + self.dut.send_expect("./examples/multi_process/client_server_mp/mp_client/client_server_mp/mp_client/%s/mp_client -n %d -c %s --proc-type=secondary -- -n %d" % (self.target, self.dut.get_memory_channels(), coreMask, n), "Finished Process Init") + self.dut.send_expect("^Z", "\r\n") + self.dut.send_expect("bg", "# ") + + tgenInput = [] + tgenInput.append([txPort, rxPort, "test.pcap"]) + _, pps = self.tester.traffic_generator_throughput(tgenInput) + execution['pps'] = pps + self.dut.kill_all() + time.sleep(5) + + for n in range(len(executions)): + self.verify(executions[n]['pps'] is not 0, "No traffic detected") + + dcts.results_table_add_header(['Server threads', 'Server Cores/Threads', 'Num-procs', 'Sockets/Cores/Threads', 'Num Ports', 'Frame Size', '%-age Line Rate', 'Packet Rate(mpps)']) + + for execution in validExecutions: + dcts.results_table_add_row([1, '1S/1C/1T', execution['nprocs'], execution['cores'], 2, 64, execution['pps'] / float(100000000 / (8 * 84)), execution['pps'] / float(1000000)]) + + dcts.results_table_print() + + def ip(self, port, frag, src, proto, tos, dst, chksum, len, options, version, flags, ihl, ttl, id): + self.add_tcl_cmd("protocol config -name ip") + self.add_tcl_cmd('ip config -sourceIpAddr "%s"' % src) + self.add_tcl_cmd('ip config -sourceIpAddrMode ipIncrHost') + self.add_tcl_cmd('ip config -sourceIpAddrRepeatCount %d' % 64) + self.add_tcl_cmd('ip config -destIpAddr "%s"' % dst) + self.add_tcl_cmd('ip config -destIpAddrMode ipIncrHost') + self.add_tcl_cmd('ip config -destIpAddrRepeatCount %d' % 64) + self.add_tcl_cmd("ip config -ttl %d" % ttl) + self.add_tcl_cmd("ip config -totalLength %d" % len) + self.add_tcl_cmd("ip config -fragment %d" % frag) + self.add_tcl_cmd("ip config -ipProtocol %d" % proto) + self.add_tcl_cmd("ip config -identifier %d" % id) + self.add_tcl_cmd("stream config -framesize %d" % (len + 18)) + self.add_tcl_cmd("ip set %d %d %d" % (self.chasId, port['card'], port['port'])) + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + self.dut.kill_all() + + pass diff --git a/tests/TestSuite_pmd.py b/tests/TestSuite_pmd.py new file mode 100644 index 0000000..502ca79 --- /dev/null +++ b/tests/TestSuite_pmd.py @@ -0,0 +1,477 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test userland 10Gb PMD + +""" + +import dcts +import re +import time +from test_case import TestCase +from plotting import Plotting +from time import sleep +from settings import HEADER_SIZE + +# +# +# Test class. +# + + +class TestPmd(TestCase): + + # + # + # Utility methods and other non-test code. + # + + def plot_results(self, number_ports): + + cores_configs = [] + percent_values = [] + + # Append the percentage results for the all the cores configs + for test_cycle in self.test_cycles: + cores_configs.append(test_cycle['cores']) + config_results = [] + for frame_size in self.frame_sizes: + config_results.append(test_cycle['pct'][frame_size]) + + percent_values.append(config_results) + + image_path = self.plotting.create_bars_plot( + 'test_perf_pmd_%sports' % number_ports, + 'PMD, %d ports' % number_ports, + self.frame_sizes, + percent_values, + ylabel='% linerate', + legend=cores_configs) + + dcts.results_plot_print(image_path) + + # + # + # + # Test cases. + # + def set_up_all(self): + """ + Run at the start of each test suite. + + PMD prerequisites. + """ + + self.frame_sizes = [64, 65, 128, 256, 512, 1024, 1280, 1518] + + self.rxfreet_values = [0, 8, 16, 32, 64, 128] + + self.test_cycles = [{'cores': '1S/1C/1T', 'Mpps': {}, 'pct': {}}, + {'cores': '1S/1C/2T', 'Mpps': {}, 'pct': {}}, + {'cores': '1S/2C/1T', 'Mpps': {}, 'pct': {}}, + {'cores': '1S/2C/2T', 'Mpps': {}, 'pct': {}}, + {'cores': '1S/4C/2T', 'Mpps': {}, 'pct': {}} + ] + + self.table_header = ['Frame Size'] + for test_cycle in self.test_cycles: + self.table_header.append("%s Mpps" % test_cycle['cores']) + self.table_header.append("% linerate") + + self.needed_ports = {"niantic": 2, + "kawela_2": 2, + "bartonhills": 4, + "82545EM": 2, + "82540EM": 2} + + self.blacklist = "" + + self.verify(self.nic in ["kawela_2", "niantic", "bartonhills", "82545EM", "82540EM"], + "NIC Unsupported: " + str(self.nic)) + + # Based on h/w type, choose how many ports to use + self.dut_ports = self.dut.get_ports(self.nic) + + # Verify that enough ports are available + self.verify(len(self.dut_ports) >= self.needed_ports[self.nic], + "Insufficient ports for speed testing") + + self.headers_size = HEADER_SIZE['eth'] + HEADER_SIZE[ + 'ip'] + HEADER_SIZE['udp'] + + self.ports_socket = self.dut.get_numa_id(self.dut_ports[0]) + + self.plotting = Plotting(self.dut.crb['name'], self.target, self.nic) + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_perf_pmd_performance_4ports(self): + """ + PMD Performance Benchmarking with 4 ports. + """ + all_cores_mask = dcts.create_mask(self.dut.get_core_list("all")) + + # prepare traffic generator input + self.verify(len(self.dut_ports) >= 4, + "Insufficient ports for 4 ports performance") + tgen_input = [] + + tgen_input.append((self.tester.get_local_port(self.dut_ports[0]), + self.tester.get_local_port(self.dut_ports[1]), + "test.pcap")) + tgen_input.append((self.tester.get_local_port(self.dut_ports[2]), + self.tester.get_local_port(self.dut_ports[3]), + "test.pcap")) + tgen_input.append((self.tester.get_local_port(self.dut_ports[1]), + self.tester.get_local_port(self.dut_ports[0]), + "test.pcap")) + tgen_input.append((self.tester.get_local_port(self.dut_ports[3]), + self.tester.get_local_port(self.dut_ports[2]), + "test.pcap")) + + # run testpmd for each core config + for test_cycle in self.test_cycles: + core_config = test_cycle['cores'] + + core_list = self.dut.get_core_list(core_config, + socket=self.ports_socket) + + if len(core_list) > 4: + queues = len(core_list) / 4 + else: + queues = 1 + + core_mask = dcts.create_mask(core_list) + port_mask = dcts.create_mask(self.dut.get_ports(self.nic)) + + commandLine = "./%s/app/testpmd -c %s -n %d %s-- -i \ +--coremask=%s --rxq=%d --txq=%d --rxd=512 --txd=512 --burst=32 --rxfreet=64 --mbcache=128 \ +--portmask=%s --txpt=36 --txht=0 --txwt=0 --txfreet=32 --txrst=32" % (self.target, + all_cores_mask, + self.dut.get_memory_channels( + ), + self.blacklist, + core_mask, + queues, + queues, + port_mask + ) + + info = "Executing PMD (mac fwd) using %s\n" % test_cycle['cores'] + dcts.report(info, annex=True) + self.logger.info(info) + + dcts.report(commandLine + "\n\n", frame=True, annex=True) + + self.dut.send_expect(commandLine, "testpmd> ", 100) + # self.dut.send_expect("set fwd mac", "testpmd> ", 100) + self.dut.send_expect("start", "testpmd> ") + + for frame_size in self.frame_sizes: + wirespeed = self.wirespeed(self.nic, frame_size, 4) + + # create pcap file + self.logger.info("Running with frame size %d " % frame_size) + payload_size = frame_size - self.headers_size + self.tester.scapy_append( + 'wrpcap("test.pcap", [Ether(src="52:00:00:00:00:00")/IP()/UDP()/("X"*%d)])' % payload_size) + self.tester.scapy_execute() + + # run traffic generator + _, pps = self.tester.traffic_generator_throughput(tgen_input) + + pps /= 1000000.0 + test_cycle['Mpps'][frame_size] = pps + test_cycle['pct'][frame_size] = pps * 100 / wirespeed + + self.dut.send_expect("stop", "testpmd> ") + self.dut.send_expect("quit", "# ", 30) + sleep(5) + + for n in range(len(self.test_cycles)): + for frame_size in self.frame_sizes: + self.verify(self.test_cycles[n]['Mpps'][ + frame_size] is not 0, "No traffic detected") + + # Print results + dcts.results_table_add_header(self.table_header) + + for frame_size in self.frame_sizes: + table_row = [frame_size] + + for test_cycle in self.test_cycles: + table_row.append(test_cycle['Mpps'][frame_size]) + table_row.append(test_cycle['pct'][frame_size]) + + dcts.results_table_add_row(table_row) + + self.plot_results(number_ports=4) + dcts.results_table_print() + + def test_perf_pmd_performance_2ports(self): + """ + PMD Performance Benchmarking with 2 ports. + """ + + all_cores_mask = dcts.create_mask(self.dut.get_core_list("all")) + + # prepare traffic generator input + tgen_input = [] + tgen_input.append((self.tester.get_local_port(self.dut_ports[0]), + self.tester.get_local_port(self.dut_ports[1]), + "test.pcap")) + tgen_input.append((self.tester.get_local_port(self.dut_ports[1]), + self.tester.get_local_port(self.dut_ports[0]), + "test.pcap")) + + # run testpmd for each core config + for test_cycle in self.test_cycles: + core_config = test_cycle['cores'] + + core_list = self.dut.get_core_list(core_config, + socket=self.ports_socket) + + if len(core_list) > 2: + queues = len(core_list) / 2 + else: + queues = 1 + + core_mask = dcts.create_mask(core_list) + port_mask = dcts.create_mask([self.dut_ports[0], self.dut_ports[1]]) + + command_line = "./%s/app/testpmd -c %s -n %d %s-- -i --coremask=%s \ +--rxq=%d --txq=%d --rxd=512 --txd=512 --burst=32 --rxfreet=64 --mbcache=128 \ +--portmask=%s --txpt=36 --txht=0 --txwt=0 --txfreet=32 --txrst=32" % (self.target, + all_cores_mask, + self.dut.get_memory_channels( + ), + self.blacklist, + core_mask, + queues, + queues, + port_mask) + + info = "Executing PMD using %s\n" % test_cycle['cores'] + self.logger.info(info) + dcts.report(info, annex=True) + dcts.report(command_line + "\n\n", frame=True, annex=True) + + self.dut.send_expect(command_line, "testpmd> ", 100) + + self.dut.send_expect("start", "testpmd> ") + for frame_size in self.frame_sizes: + wirespeed = self.wirespeed(self.nic, frame_size, 2) + + # create pcap file + self.logger.info("Running with frame size %d " % frame_size) + payload_size = frame_size - self.headers_size + self.tester.scapy_append( + 'wrpcap("test.pcap", [Ether(src="52:00:00:00:00:00")/IP()/UDP()/("X"*%d)])' % payload_size) + self.tester.scapy_execute() + + # run traffic generator + _, pps = self.tester.traffic_generator_throughput(tgen_input) + + pps /= 1000000.0 + test_cycle['Mpps'][frame_size] = pps + test_cycle['pct'][frame_size] = pps * 100 / wirespeed + + self.dut.send_expect("stop", "testpmd> ") + self.dut.send_expect("quit", "# ", 30) + sleep(5) + + for n in range(len(self.test_cycles)): + for frame_size in self.frame_sizes: + self.verify(self.test_cycles[n]['Mpps'][ + frame_size] > 0, "No traffic detected") + + # Print results + dcts.results_table_add_header(self.table_header) + for frame_size in self.frame_sizes: + table_row = [frame_size] + for test_cycle in self.test_cycles: + table_row.append(test_cycle['Mpps'][frame_size]) + table_row.append(test_cycle['pct'][frame_size]) + + dcts.results_table_add_row(table_row) + + self.plot_results(number_ports=2) + dcts.results_table_print() + + def test_checksum_checking(self): + """ + Packet forwarding checking test + """ + + self.dut.kill_all() + + all_cores_mask = dcts.create_mask(self.dut.get_core_list("all")) + core_mask = dcts.create_mask(self.dut.get_core_list('1S/1C/1T', + socket=self.ports_socket)) + port_mask = dcts.create_mask([self.dut_ports[0], self.dut_ports[1]]) + + for rxfreet_value in self.rxfreet_values: + + cmd = "./%s/app/testpmd -c %s -n %d %s-- \ +--coremask=%s --portmask=%s --nb-cores=2 --enable-rx-cksum --disable-hw-vlan \ +--disable-rss --crc-strip --rxd=1024 --txd=1024 --rxfreet=%d -i" % (self.target, + all_cores_mask, + self.dut.get_memory_channels(), + self.blacklist, + core_mask, + port_mask, + rxfreet_value + ) + + self.dut.send_expect(cmd, "testpmd> ", 120) + # self.dut.send_expect("set fwd csum", "testpmd> ") + self.dut.send_expect("start", "testpmd> ") + + self.send_packet(self.frame_sizes[0], checksum_test=True) + + l4csum_error = self.stop_and_get_l4csum_errors() + + # Check the l4 checksum errors reported for Rx port + self.verify(1 == int(l4csum_error[1]), + "Wrong l4 checksum error count using rxfreet=%d (expected 1, reported %s)" % + (rxfreet_value, l4csum_error[1])) + + self.dut.send_expect("quit", "# ", 30) + sleep(5) + + def test_packet_checking(self): + """ + Packet forwarding checking test + """ + + self.dut.kill_all() + + all_cores_mask = dcts.create_mask(self.dut.get_core_list("all")) + core_mask = dcts.create_mask(self.dut.get_core_list('1S/1C/1T', + socket=self.ports_socket)) + port_mask = dcts.create_mask([self.dut_ports[0], self.dut_ports[1]]) + + cmd = "./%s/app/testpmd -c %s -n %d %s-- -i \ +--coremask=%s --rxd=512 --txd=512 --burst=32 --rxfreet=64 --mbcache=128 \ +--portmask=%s --txpt=36 --txht=0 --txwt=0 --txfreet=32 --txrst=32" % (self.target, + all_cores_mask, + self.dut.get_memory_channels( + ), + self.blacklist, + core_mask, + port_mask + ) + + self.dut.send_expect(cmd, "testpmd> ", 120) + self.dut.send_expect("start", "testpmd> ") + for size in self.frame_sizes: + self.send_packet(size) + + self.dut.send_expect("stop", "testpmd> ") + self.dut.send_expect("quit", "# ", 30) + sleep(5) + + def stop_and_get_l4csum_errors(self): + """ + Stop forwarding and get Bad-l4csum number from stop statistic + """ + + out = self.dut.send_expect("stop", "testpmd> ") + result_scanner = r"Bad-l4csum: ([0-9]+) \s*" + scanner = re.compile(result_scanner, re.DOTALL) + m = scanner.findall(out) + + return m + + def get_stat(self, portid, rx_tx): + """ + Get packets number from port statistic + """ + + out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ") + + if rx_tx == "rx": + result_scanner = r"RX-packets: ([0-9]+) \s* RX-errors: ([0-9]+) \s* RX-bytes: ([0-9]+)" + elif rx_tx == "tx": + result_scanner = r"TX-packets: ([0-9]+) \s* TX-errors: ([0-9]+) \s* TX-bytes: ([0-9]+)" + else: + return None + + scanner = re.compile(result_scanner, re.DOTALL) + m = scanner.search(out) + + return m.groups() + + def send_packet(self, frame_size, checksum_test=False): + """ + Send 1 packet to portid + """ + + gp0tx_pkts, _, gp0tx_bytes = [int( + _) for _ in self.get_stat(self.dut_ports[0], "tx")] + gp1rx_pkts, gp1rx_err, gp1rx_bytes = [int( + _) for _ in self.get_stat(self.dut_ports[1], "rx")] + + interface = self.tester.get_interface( + self.tester.get_local_port(self.dut_ports[1])) + mac = self.dut.get_mac_address(self.dut_ports[1]) + + load_size = frame_size - HEADER_SIZE['eth'] + padding = frame_size - HEADER_SIZE['eth'] - HEADER_SIZE['ip'] - \ + HEADER_SIZE['udp'] + + checksum = '' + if checksum_test: + checksum = 'chksum=0x0' + + self.tester.scapy_foreground() + self.tester.scapy_append('nutmac="%s"' % mac) + self.tester.scapy_append('sendp([Ether(dst=nutmac, src="52:00:00:00:00:00")/IP(len=%s)/UDP(%s)/Raw(load="\x50"*%s)], iface="%s")' % ( + load_size, checksum, padding, interface)) + + out = self.tester.scapy_execute() + time.sleep(.5) + + p0tx_pkts, _, p0tx_bytes = [int(_) for _ in self.get_stat( + self.dut_ports[0], "tx")] + p1rx_pkts, p1rx_err, p1rx_bytes = [int( + _) for _ in self.get_stat(self.dut_ports[1], "rx")] + + p0tx_pkts -= gp0tx_pkts + p0tx_bytes -= gp0tx_bytes + p1rx_pkts -= gp1rx_pkts + p1rx_bytes -= gp1rx_bytes + p1rx_err -= gp1rx_err + + self.verify(p0tx_pkts == p1rx_pkts, + "packet pass assert error, %d RX packets, %d TX packets" % (p1rx_pkts, p0tx_pkts)) + + if checksum_test: + self.verify(p1rx_bytes == frame_size - 4, + "packet pass assert error, expected %d RX bytes, actual %d" % (frame_size - 4, p1rx_bytes)) + else: + self.verify(p1rx_bytes == frame_size, + "packet pass assert error, expected %d RX bytes, actual %d" % (frame_size, p1rx_bytes)) + + self.verify(p0tx_bytes == frame_size, + "packet pass assert error, expected %d TX bytes, actual %d" % (frame_size, p0tx_bytes)) + + return out + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + self.dut.kill_all() diff --git a/tests/TestSuite_pmd_bonded.py b/tests/TestSuite_pmd_bonded.py new file mode 100644 index 0000000..3553a5f --- /dev/null +++ b/tests/TestSuite_pmd_bonded.py @@ -0,0 +1,1098 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + + +Test userland 10Gb PMD. + +""" + +import time +import re +import random +from socket import htons, htonl +import pdb + +import dcts +from test_case import TestCase + +# +# +# Test class. +# + + +class TestPmdBonded(TestCase): + + # + # + # Utility methods and other non-test code. + # + # Insert or move non-test functions here. + + def get_stats(self, portid, rx_tx): + """ + Get packets number from port statistic + """ + + out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ") + + if rx_tx == "rx": + result_scanner = r"RX-packets: ([0-9]+)\s*RX-missed: ([0-9]+)\s*RX-bytes: ([0-9]+)" + elif rx_tx == "tx": + result_scanner = r"TX-packets: ([0-9]+)\s*TX-errors: ([0-9]+)\s*TX-bytes: ([0-9]+)" + else: + return None + + scanner = re.compile(result_scanner, re.DOTALL) + m = scanner.search(out) + + return m.groups() + + def send_packet(self, port_id, frame_size=64, count=1, reverse_verify=False, **ether_ip): + """ + Send count packet to portid + ether_ip: + 'ether': + { + 'dest_mac':False + 'src_mac':"52:00:00:00:00:00" + } + 'dot1q': + { + 'vlan':1 + } + 'ip': + { + 'dest_ip':"10.239.129.88" + 'src_ip':"10.239.129.65" + } + 'udp': + { + 'dest_port':53 + 'src_port':53 + } + """ + + gp0rx_pkts, gp0rx_err, gp0rx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[port_id], "rx")] + + itf = self.tester.get_interface(self.tester.get_local_port(self.dut_ports[port_id])) + + if not ether_ip.get('ether'): + dest_mac = self.dut.get_mac_address(self.dut_ports[port_id]) + src_mac = "52:00:00:00:00:00" + else: + if not ether_ip['ether'].get('dest_mac'): + dest_mac = self.dut.get_mac_address(self.dut_ports[port_id]) + else: + dest_mac = ether_ip['ether']['dest_mac'] + if not ether_ip['ether'].get('src_mac'): + src_mac = "52:00:00:00:00:00" + else: + src_mac = ether_ip["ether"]["src_mac"] + + if not ether_ip.get('dot1q'): + pass + else: + if not ether_ip['dot1q'].get('vlan'): + vlan = '1' + else: + vlan = ether_ip['dot1q']['vlan'] + + if not ether_ip.get('ip'): + dest_ip = "10.239.129.88" + src_ip = "10.239.129.65" + else: + if not ether_ip['ip'].get('dest_ip'): + dest_ip = "10.239.129.88" + else: + dest_ip = ether_ip['ip']['dest_ip'] + if not ether_ip['ip'].get('src_ip'): + src_ip = "10.239.129.65" + else: + src_ip = ether_ip['ip']['src_ip'] + + if not ether_ip.get('udp'): + dest_port = 53 + src_port = 53 + else: + if not ether_ip['udp'].get('dest_port'): + dest_port = 53 + else: + dest_port = ether_ip['udp']['dest_port'] + if not ether_ip['udp'].get('src_port'): + src_port = 53 + else: + src_port = ether_ip['udp']['src_port'] + + pktlen = frame_size - 18 + padding = pktlen - 20 + + self.tester.scapy_foreground() + self.tester.scapy_append('nutmac="%s"' % dest_mac) + self.tester.scapy_append('srcmac="%s"' % src_mac) + + if ether_ip.get('dot1q'): + self.tester.scapy_append('vlanvalue=%d' % vlan) + self.tester.scapy_append('destip="%s"' % dest_ip) + self.tester.scapy_append('srcip="%s"' % src_ip) + self.tester.scapy_append('destport=%d' % dest_port) + self.tester.scapy_append('srcport=%d' % src_port) + if not ether_ip.get('dot1q'): + self.tester.scapy_append('sendp([Ether(dst=nutmac, src=srcmac)/IP(dst=destip, src=srcip, len=%s)/\ +UDP(sport=srcport, dport=destport)/Raw(load="\x50"*%s)], iface="%s", count=%d)' % (pktlen, padding, itf, count)) + else: + self.tester.scapy_append('sendp([Ether(dst=nutmac, src=srcmac)/Dot1Q(vlan=vlanvalue)/IP(dst=destip, src=srcip, len=%s)/\ +UDP(sport=srcport, dport=destport)/Raw(load="\x50"*%s)], iface="%s", count=%d)' % (pktlen, padding, itf, count)) + + out = self.tester.scapy_execute() + time.sleep(.5) + + p0rx_pkts, p0rx_err, p0rx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[port_id], "rx")] + + p0rx_pkts -= gp0rx_pkts + + if not reverse_verify: + self.verify(p0rx_pkts == count, "Data not received by port") + else: + self.verify(p0rx_pkts == 0, "Data received by port,should not received") + return out + + # + # + # + # Test cases. + # + def set_up_all(self): + """ + Run before each test suite + """ + self.verify('bsdapp' not in self.target, "Bonding not support freebsd") + self.frame_sizes = [64, 65, 128, 256, 512, 1024, 1280, 1518] + + self.eth_head_size = 18 + self.ip_head_size = 20 + self.udp_header_size = 8 + + self.dut_ports = self.dut.get_ports(self.nic) + + self.port_mask = dcts.create_mask(self.dut_ports) + + self.verify(len(self.dut_ports) >= 4, "Insufficient ports") + + self.ports_socket = self.dut.get_numa_id(self.dut_ports[0]) + + self.all_cores_mask = dcts.create_mask(self.dut.get_core_list("all")) + + def set_up(self): + """ + Run before each test case. + """ + pass + + def get_value_from_str(self, key_str, regx_str, string): + pattern = r"(?<=%s)%s" % (key_str, regx_str) + s = re.compile(pattern) + res = s.search(string) + if type(res).__name__ == 'NoneType': + return ' ' + else: + return res.group(0) + + def get_detail_from_port_info(self, key_str, regx_str, port): + out = self.dut.send_expect("show port info %d" % port, "testpmd> ") + find_value = self.get_value_from_str(key_str, regx_str, out) + return find_value + + def get_port_mac(self, port_id): + return self.get_detail_from_port_info("MAC address: ", "([0-9A-F]{2}:){5}[0-9A-F]{2}", port_id) + + def get_port_connect_socket(self, port_id): + return self.get_detail_from_port_info("Connect to socket: ", "\d+", port_id) + + def get_port_memory_socket(self, port_id): + return self.get_detail_from_port_info("memory allocation on the socket: ", "\d+", port_id) + + def get_port_link_status(self, port_id): + return self.get_detail_from_port_info("Link status: ", "\d+", port_id) + + def get_port_link_speed(self, port_id): + return self.get_detail_from_port_info("Link speed: ", "\d+", port_id) + + def get_port_link_duplex(self, port_id): + return self.get_detail_from_port_info("Link duplex: ", "\S+", port_id) + + def get_port_promiscuous_mode(self, port_id): + return self.get_detail_from_port_info("Promiscuous mode: ", "\S+", port_id) + + def get_port_allmulticast_mode(self, port_id): + return self.get_detail_from_port_info("Allmulticast mode: ", "\S+", port_id) + + def get_port_vlan_offload(self, port_id): + """ + return value: + 'strip':'on' + 'filter':'on' + 'qinq':'off' + """ + vlan_info = {} + vlan_info['strip'] = self.get_detail_from_port_info("strip ", '\S+', port_id) + vlan_info['filter'] = self.get_detail_from_port_info('filter', '\S+', port_id) + vlan_info['qinq'] = self.get_detail_from_port_info('qinq\(extend\) ', '\S+', port_id) + return vlan_info + + def get_info_from_bond_config(self, key_str, regx_str, bond_port): + out = self.dut.send_expect("show bonding config %d" % bond_port, "testpmd> ") + find_value = self.get_value_from_str(key_str, regx_str, out) + return find_value + + def get_bond_mode(self, bond_port): + return self.get_info_from_bond_config("Bonding mode: ", "\d*", bond_port) + + def get_bond_balance_policy(self, bond_port): + return self.get_info_from_bond_config("Balance Xmit Policy: ", "\S+", bond_port) + + def get_bond_slaves(self, bond_port): + try: + return self.get_info_from_bond_config("Slaves \(\d\): \[", "\d*( \d*)*", bond_port) + except Exception as e: + return self.get_info_from_bond_config("Slaves: \[", "\d*( \d*)*", bond_port) + + def get_bond_active_slaves(self, bond_port): + try: + return self.get_info_from_bond_config("Active Slaves \(\d\): \[", "\d*( \d*)*", bond_port) + except Exception as e: + return self.get_info_from_bond_config("Acitve Slaves: \[", "\d*( \d*)*", bond_port) + + def get_bond_primary(self, bond_port): + return self.get_info_from_bond_config("Primary: \[", "\d*", bond_port) + + def launch_app(self, cmd_param="-c 0xf -n 4 -- -i"): + app_path = "./%s/app/testpmd" % self.target + self.dut.send_expect(app_path + ' ' + cmd_param, "testpmd> ", 120) + + def create_bonded_device(self, mode=0, socket=0, verify_detail=False): + out = self.dut.send_expect("create bonded device %d %d" % (mode, socket), "testpmd> ") + self.verify("Created new bonded device" in out, "Create bonded device on mode [%d] socket [%d] failed" % (mode, socket)) + bond_port = self.get_value_from_str("Created new bonded device eth_bond_testpmd_[\d] on \(port ", "\d+", out) + bond_port = int(bond_port) + + if verify_detail: + out = self.dut.send_expect("show bonding config %d" % bond_port, "testpmd> ") + self.verify("Bonding mode: %d" % mode in out, "Bonding mode display error when create bonded device") + self.verify("Slaves: []" in out, "Slaves display error when create bonded device") + self.verify("Active Slaves: []" in out, "Active Slaves display error when create bonded device") + self.verify("Primary: []" not in out, "Primary display error when create bonded device") + + out = self.dut.send_expect("show port info %d" % bond_port, "testpmd> ") + self.verify("Connect to socket: %d" % socket in out, "Bonding port connect socket error") + self.verify("Link status: down" in out, "Bonding port default link status error") + self.verify("Link speed: 0 Mbps" in out, "Bonding port default link speed error") + + return bond_port + + def start_all_ports(self): + self.dut.send_expect("port start all", "testpmd> ") + time.sleep(5) + + def add_slave_to_bonding_device(self, bond_port, reverse_verify=False, *slave_port): + if len(slave_port) <= 0: + dcts.RED("No port exist when add slave to bonded device") + for slave_id in slave_port: + self.dut.send_expect("add bonding slave %d %d" % (slave_id, bond_port), "testpmd> ") + + slaves = self.get_info_from_bond_config("Slaves \(\d\): \[", "\d*( \d*)*", bond_port) + if not reverse_verify: + self.verify(str(slave_id) in slaves, "Add port as bonding slave failed") + else: + self.verify(str(slave_id) not in slaves, "Add port as bonding slave successfully,should fail") + + def remove_slave_from_bonding_device(self, bond_port, reverse_verify=False, *slave_port): + if len(slave_port) <= 0: + dcts.RED("No port exist when remove slave from bonded device") + for slave_id in slave_port: + self.dut.send_expect("remove bonding slave %d %d" % (slave_id, bond_port), "testpmd> ") + out = self.get_info_from_bond_config("Slaves: \[", "\d*( \d*)*", bond_port) + if not reverse_verify: + self.verify(str(slave_id) not in out, "Remove slave to fail from bonding device") + else: + self.verify(str(slave_id) in out, "Remove slave successfully from bonding device,should be failed") + + def set_primary_for_bonding_device(self, bond_port, slave_port, reverse_verify=False): + self.dut.send_expect("set bonding primary %d %d" % (slave_port, bond_port), "testpmd> ") + out = self.get_info_from_bond_config("Primary: \[", "\d*", bond_port) + if not reverse_verify: + self.verify(str(slave_port) in out, "Set bonding primary port failed") + else: + self.verify(str(slave_port) not in out, "Set bonding primary port successfully,should not success") + + def set_mode_for_bonding_device(self, bond_port, mode): + self.dut.send_expect("set bonding mode %d %d" % (mode, bond_port), "testpmd> ") + mode_value = self.get_bond_mode(bond_port) + self.verify(str(mode) in mode_value, "Set bonding mode failed") + + def set_mac_for_bonding_device(self, bond_port, mac): + self.dut.send_expect("set bonding mac_addr %s %s" % (bond_port, mac), "testpmd> ") + new_mac = self.get_port_mac(bond_port) + self.verify(new_mac == mac, "Set bonding mac failed") + + def set_balance_policy_for_bonding_device(self, bond_port, policy): + self.dut.send_expect("set bonding balance_xmit_policy %d %s" % (bond_port, policy), "testpmd> ") + new_policy = self.get_bond_balance_policy(bond_port) + policy = "BALANCE_XMIT_POLICY_LAYER" + policy.lstrip('l') + self.verify(new_policy == policy, "Set bonding balance policy failed") + + def test_create_bonded_devices_and_slaves(self): + """ + Create bonded devices and slaves. + """ + self.launch_app() + bond_port_0 = self.create_bonded_device(1, 0, True) + self.add_slave_to_bonding_device(bond_port_0, False, self.dut_ports[1]) + self.start_all_ports() + mode_value = self.get_bond_mode(bond_port_0) + self.verify('1' in mode_value, "Bonding mode show error") + slaves = self.get_bond_slaves(bond_port_0) + self.verify(str(self.dut_ports[1]) in slaves, "Bonding slaves show error") + primary = self.get_bond_primary(bond_port_0) + self.verify(str(self.dut_ports[1]) in primary, "Bonding primary show error") + + bond_port_1 = self.create_bonded_device(1, 0) + self.add_slave_to_bonding_device(bond_port_0, False, self.dut_ports[0]) + self.add_slave_to_bonding_device(bond_port_1, True, self.dut_ports[0]) + + self.set_mode_for_bonding_device(bond_port_0, 3) + self.add_slave_to_bonding_device(bond_port_0, False, self.dut_ports[2]) + time.sleep(5) + self.set_primary_for_bonding_device(bond_port_0, self.dut_ports[2]) + + self.remove_slave_from_bonding_device(bond_port_0, False, self.dut_ports[1]) + self.remove_slave_from_bonding_device(bond_port_0, False, self.dut_ports[0]) + self.remove_slave_from_bonding_device(bond_port_0, False, self.dut_ports[2]) + + def test_bonded_mac_address(self): + """ + Create bonded device, add one slave, verify bonded device MAC address is the slave's MAC. + """ + self.launch_app() + bond_port = self.create_bonded_device(3, 1) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[1]) + mac_address_0_orig = self.get_port_mac(self.dut_ports[0]) + mac_address_1_orig = self.get_port_mac(self.dut_ports[1]) + mac_address_2_orig = self.get_port_mac(self.dut_ports[2]) + mac_address_3_orig = self.get_port_mac(self.dut_ports[3]) + mac_address_bond_orig = self.get_port_mac(bond_port) + self.verify(mac_address_1_orig == mac_address_bond_orig, "Bonded device MAC address not same with first slave MAC") + + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[2]) + mac_address_2_now = self.get_port_mac(self.dut_ports[2]) + mac_address_bond_now = self.get_port_mac(bond_port) + self.verify(mac_address_1_orig == mac_address_bond_now and mac_address_bond_now == mac_address_2_now, + "NOT all slaves MAC address same with bonding device") + + new_mac = "00:11:22:00:33:44" + self.set_mac_for_bonding_device(bond_port, new_mac) + mac_address_1_now = self.get_port_mac(self.dut_ports[1]) + mac_address_2_now = self.get_port_mac(self.dut_ports[2]) + mac_address_bond_now = self.get_port_mac(bond_port) + self.verify(mac_address_1_now == mac_address_2_now == mac_address_bond_now == new_mac, + "Set mac failed for bonding device") + + self.dut.send_expect("port start %d" % bond_port, "testpmd> ") + time.sleep(5) + self.set_primary_for_bonding_device(bond_port, self.dut_ports[2], False) + mac_address_1_now = self.get_port_mac(self.dut_ports[1]) + mac_address_2_now = self.get_port_mac(self.dut_ports[2]) + mac_address_bond_now = self.get_port_mac(bond_port) + self.verify(mac_address_1_now == mac_address_2_now == mac_address_bond_now == new_mac, + "Slave MAC changed when set primary slave") + self.remove_slave_from_bonding_device(bond_port, False, self.dut_ports[2]) + primary_now = self.get_bond_primary(bond_port) + self.verify(int(primary_now) == self.dut_ports[1], "Reset primary slave failed after removing primary slave") + mac_address_2_now = self.get_port_mac(self.dut_ports[2]) + self.verify(mac_address_2_now == mac_address_2_orig, "MAC not back to original after removing the port") + mac_address_1_now = self.get_port_mac(self.dut_ports[1]) + mac_address_bond_now = self.get_port_mac(bond_port) + self.verify(mac_address_1_now == mac_address_bond_now == new_mac, + "Bonding device and slave MAC changed after removing the primary slave") + + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[3]) + self.remove_slave_from_bonding_device(bond_port, False, self.dut_ports[3]) + mac_address_3_now = self.get_port_mac(self.dut_ports[3]) + self.verify(mac_address_3_now == mac_address_3_orig, "Slave MAC not back to original after removing it") + + def test_device_promiscuous_mode(self): + self.launch_app() + bond_port = self.create_bonded_device(3, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + port_enabled_num = 0 + for port_id in [0, 1, 2, 4]: + value = self.get_detail_from_port_info("Promiscuous mode: ", "enabled", port_id) + if value: + port_enabled_num += 1 + self.verify(port_enabled_num == 4, "Not all slaves of bonded device changed to promiscuous mode.") + + ether_ip = {} + ether = {} + ether['dest_mac'] = "00:11:22:33:44:55" + ether_ip['ether'] = ether + + pkt_count = 1 + + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + gp0rx_pkts, gp0rx_err, gp0rx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[0], "rx")] + gp4rx_pkts, gp4rx_err, gp4rx_bytes = [int(_) for _ in self.get_stats(bond_port, "rx")] + self.send_packet(self.dut_ports[0], 64, pkt_count, False, **ether_ip) + p0rx_pkts, p0rx_err, p0rx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[0], "rx")] + p4rx_pkts, p4rx_err, p4rx_bytes = [int(_) for _ in self.get_stats(bond_port, "rx")] + p0rx_pkts -= gp0rx_pkts + p4rx_pkts -= gp4rx_pkts + self.verify(p0rx_pkts == pkt_count and p4rx_pkts == pkt_count, "Data not received by slave or bonding device when promiscuous state") + + self.dut.send_expect("set promisc 4 off", "testpmd> ") + port_disabled_num = 0 + for port_id in [0, 1, 2, 4]: + value = self.get_detail_from_port_info('Promiscuous mode: ', 'disabled', port_id) + if value: + port_disabled_num += 1 + self.verify(port_disabled_num == 4, "Not all slaves of bonded device make promiscuous mode disabled.") + + gp0rx_pkts, gp0rx_err, gp0rx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[0], "rx")] + gp4rx_pkts, gp4rx_err, gp4rx_bytes = [int(_) for _ in self.get_stats(bond_port, "rx")] + self.send_packet(self.dut_ports[0], 64, pkt_count, True, **ether_ip) + p0rx_pkts, p0rx_err, p0rx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[0], "rx")] + p4rx_pkts, p4rx_err, p4rx_bytes = [int(_) for _ in self.get_stats(bond_port, "rx")] + p0rx_pkts -= gp0rx_pkts + p4rx_pkts -= gp4rx_pkts + self.verify(p0rx_pkts == 0 and p4rx_pkts == 0, "Data received by slave or bonding device when promiscuous disabled") + + gp0rx_pkts, gp0rx_err, gp0rx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[0], "rx")] + gp3tx_pkts, gp3tx_err, gp3tx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[3], "tx")] + gp4rx_pkts, gp4rx_err, gp4rx_bytes = [int(_) for _ in self.get_stats(bond_port, "rx")] + self.send_packet(self.dut_ports[0], 64, pkt_count) + p0rx_pkts, p0rx_err, p0rx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[0], "rx")] + p3tx_pkts, p3tx_err, p3tx_bytes = [int(_) for _ in self.get_stats(self.dut_ports[3], "tx")] + p4rx_pkts, p4rx_err, p4rx_bytes = [int(_) for _ in self.get_stats(bond_port, "rx")] + p0rx_pkts -= gp0rx_pkts + p3tx_pkts -= gp3tx_pkts + p4rx_pkts -= gp4rx_pkts + self.verify(p0rx_pkts == p4rx_pkts == p3tx_pkts == pkt_count, "RX or TX packet number not correct when promiscuous disabled") + + def admin_tester_port(self, local_port, status): + if self.tester.get_os_type() == 'freebsd': + self.tester.admin_ports(local_port, status) + else: + eth = self.tester.get_interface(local_port) + self.tester.admin_ports_linux(eth, status) + time.sleep(5) + + def verify_round_robin_rx_tx(self, unbond_port, bond_port, **slaves): + """ + slaves: + 'active' = [] + 'inactive' = [] + """ + pkt_count = 300 + tx_pkt_orig = {} + tx_pkt_now = {} + + # send to unbonding port + for slave in slaves['active']: + tx_pkt_orig[slave] = [int(_) for _ in self.get_stats(slave, "tx")] + for slave in slaves['inactive']: + tx_pkt_orig[slave] = [int(_) for _ in self.get_stats(slave, "tx")] + tx_pkt_orig[bond_port] = [int(_) for _ in self.get_stats(bond_port, "tx")] + + self.send_packet(unbond_port, 64, pkt_count) + + for slave in slaves['active']: + tx_pkt_now[slave] = [int(_) for _ in self.get_stats(slave, "tx")] + tx_pkt_now[slave][0] -= tx_pkt_orig[slave][0] + for slave in slaves['inactive']: + tx_pkt_now[slave] = [int(_) for _ in self.get_stats(slave, "tx")] + tx_pkt_now[slave][0] -= tx_pkt_orig[slave][0] + tx_pkt_now[bond_port] = [int(_) for _ in self.get_stats(bond_port, "tx")] + tx_pkt_now[bond_port][0] -= tx_pkt_orig[bond_port][0] + + if slaves['active'].__len__() == 0: + self.verify(tx_pkt_now[bond_port][0] == 0, "Bonding port should not have TX pkt in mode 0 when all slaves down") + else: + self.verify(tx_pkt_now[bond_port][0] == pkt_count, "Bonding port has error TX pkt count in mode 0") + for slave in slaves['active']: + self.verify(tx_pkt_now[slave][0] == pkt_count / slaves['active'].__len__(), "Active slave has error TX pkt count in mode 0") + for slave in slaves['inactive']: + self.verify(tx_pkt_now[slave][0] == 0, "Inactive slave has error TX pkt count in mode 0") + + # send to bonding slaves + pkt_orig = {} + pkt_now = {} + pkt_orig[unbond_port] = [int(_) for _ in self.get_stats(unbond_port, "tx")] + pkt_orig[bond_port] = [int(_) for _ in self.get_stats(bond_port, "rx")] + + for slave in slaves['active']: + self.send_packet(slave, 64, pkt_count) + for slave in slaves['inactive']: + self.send_packet(slave, 64, pkt_count, True) + + pkt_now[unbond_port] = [int(_) for _ in self.get_stats(unbond_port, "tx")] + pkt_now[bond_port] = [int(_) for _ in self.get_stats(bond_port, "rx")] + pkt_now[unbond_port][0] -= pkt_orig[unbond_port][0] + pkt_now[bond_port][0] -= pkt_orig[bond_port][0] + + self.verify(pkt_now[unbond_port][0] == pkt_count * slaves['active'].__len__(), "Unbonded port has error TX pkt count in mode 0") + self.verify(pkt_now[bond_port][0] == pkt_count * slaves['active'].__len__(), "Bonding port has error RX pkt count in mode 0") + + def test_round_robin_rx_tx(self): + self.launch_app() + bond_port = self.create_bonded_device(0, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + + slaves = {} + slaves['active'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + slaves['inactive'] = [] + self.verify_round_robin_rx_tx(self.dut_ports[3], bond_port, **slaves) + + def test_round_robin_one_slave_down(self): + self.launch_app() + bond_port = self.create_bonded_device(0, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "down") + + stat = self.tester.get_port_status(self.tester.get_local_port(self.dut_ports[0])) + self.dut.send_expect("show bonding config %d" % bond_port, "testpmd> ") + self.dut.send_expect("show port info all", "testpmd> ") + + try: + slaves = {} + slaves['active'] = [self.dut_ports[1], self.dut_ports[2]] + slaves['inactive'] = [self.dut_ports[0]] + self.verify_round_robin_rx_tx(self.dut_ports[3], bond_port, **slaves) + finally: + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "up") + + def test_round_robin_all_slave_down(self): + self.launch_app() + bond_port = self.create_bonded_device(0, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "down") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[1]), "down") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[2]), "down") + + try: + slaves = {} + slaves['active'] = [] + slaves['inactive'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + self.verify_round_robin_rx_tx(self.dut_ports[3], bond_port, **slaves) + finally: + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "up") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[1]), "up") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[2]), "up") + + def get_all_stats(self, unbond_port, rx_tx, bond_port, **slaves): + """ + unbond_port: pmd port id + rx_tx: 'rx' or 'tx' + bond_port: bonding port + slaves: + 'active' = [] + 'inactive' = [] + """ + pkt_now = {} + + if rx_tx == 'rx': + bond_stat = 'tx' + else: + bond_stat = 'rx' + + pkt_now[unbond_port] = [int(_) for _ in self.get_stats(unbond_port, rx_tx)] + pkt_now[bond_port] = [int(_) for _ in self.get_stats(bond_port, bond_stat)] + for slave in slaves['active']: + pkt_now[slave] = [int(_) for _ in self.get_stats(slave, bond_stat)] + for slave in slaves['inactive']: + pkt_now[slave] = [int(_) for _ in self.get_stats(slave, bond_stat)] + + return pkt_now + + def verify_active_backup_rx_tx(self, unbond_port, bond_port, **slaves): + """ + slaves: + 'active' = [] + 'inactive' = [] + """ + pkt_count = 100 + pkt_orig = {} + pkt_now = {} + + if slaves['active'].__len__() != 0: + primary_port = slaves['active'][0] + active_flag = 1 + else: + reverse_verify = True + active_flag = 0 + + # send to unbond port + pkt_orig = self.get_all_stats(unbond_port, 'rx', bond_port, **slaves) + self.send_packet(unbond_port, 64, pkt_count) + pkt_now = self.get_all_stats(unbond_port, 'rx', bond_port, **slaves) + + for key in pkt_now: + for num in [0, 1, 2]: + pkt_now[key][num] -= pkt_orig[key][num] + + if active_flag == 1: + self.verify(pkt_now[primary_port][0] == pkt_count, "Active port not correct TX pkt in mode 1") + self.verify(pkt_now[bond_port][0] == pkt_count * active_flag, "Bond port not correct TX pkt in mode 1") + for slave in slaves['inactive']: + self.verify(pkt_now[slave][0] == 0, "Backup port not correct TX pkt in mode 1") + + # send to primary slave + if active_flag == 1: + pkt_orig = self.get_all_stats(unbond_port, 'tx', bond_port, **slaves) + self.send_packet(primary_port, 64, pkt_count) + pkt_now = self.get_all_stats(unbond_port, 'tx', bond_port, **slaves) + + pkt_now[bond_port][0] -= pkt_orig[bond_port][0] + pkt_now[unbond_port][0] -= pkt_orig[bond_port][0] + for key in pkt_now: + for num in [0, 1, 2]: + pkt_now[key][num] -= pkt_orig[key][num] + + self.verify(pkt_now[bond_port][0] == pkt_count, "Bond port not correct RX pkt in mode 1") + self.verify(pkt_now[unbond_port][0] == pkt_count, "Unbond port not correct TX pkt in mode 1") + for slave in slaves['inactive']: + self.verify(pkt_now[slave][0] == 0, "Backup port not correct RX pkt in mode 1") + + def test_active_backup_rx_tx(self): + self.launch_app() + bond_port = self.create_bonded_device(1, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + time.sleep(5) + + slaves = {} + slaves['active'] = [self.dut_ports[0]] + slaves['inactive'] = [self.dut_ports[1], self.dut_ports[2]] + self.verify_active_backup_rx_tx(self.dut_ports[3], bond_port, **slaves) + + def test_active_backup_change_primary(self): + self.launch_app() + bond_port = self.create_bonded_device(1, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + self.set_primary_for_bonding_device(bond_port, self.dut_ports[1]) + time.sleep(5) + + slaves = {} + slaves['active'] = [self.dut_ports[1]] + slaves['inactive'] = [self.dut_ports[0], self.dut_ports[2]] + self.verify_active_backup_rx_tx(self.dut_ports[3], bond_port, **slaves) + + def test_active_backup_one_slave_down(self): + self.launch_app() + bond_port = self.create_bonded_device(1, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "down") + primary_port = int(self.get_bond_primary(bond_port)) + + try: + slaves = {} + slaves['active'] = [primary_port] + slaves['inactive'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + slaves['inactive'].remove(primary_port) + self.verify_active_backup_rx_tx(self.dut_ports[3], bond_port, **slaves) + finally: + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "up") + + def test_active_backup_all_slave_down(self): + self.launch_app() + bond_port = self.create_bonded_device(1, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "down") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[1]), "down") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[2]), "down") + + try: + slaves = {} + slaves['active'] = [] + slaves['inactive'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + self.verify_active_backup_rx_tx(self.dut_ports[3], bond_port, **slaves) + finally: + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "up") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[1]), "up") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[2]), "up") + + def translate_mac_str_into_int(self, mac_str): + mac_hex = '0x' + for mac_part in mac_str.split(':'): + mac_hex += mac_part + return int(mac_hex, 16) + + def mac_hash(self, dest_mac, src_mac): + dest_port_mac = self.translate_mac_str_into_int(dest_mac) + src_port_mac = self.translate_mac_str_into_int(src_mac) + src_xor_dest = dest_port_mac ^ src_port_mac + xor_value_1 = src_xor_dest >> 32 + xor_value_2 = (src_xor_dest >> 16) ^ (xor_value_1 << 16) + xor_value_3 = src_xor_dest ^ (xor_value_1 << 32) ^ (xor_value_2 << 16) + return htons(xor_value_1 ^ xor_value_2 ^ xor_value_3) + + def translate_ip_str_into_int(self, ip_str): + ip_part_list = ip_str.split('.') + ip_part_list.reverse() + num = 0 + ip_int = 0 + for ip_part in ip_part_list: + ip_part_int = int(ip_part) << (num * 8) + ip_int += ip_part_int + num += 1 + return ip_int + + def ipv4_hash(self, dest_ip, src_ip): + dest_ip_int = self.translate_ip_str_into_int(dest_ip) + src_ip_int = self.translate_ip_str_into_int(src_ip) + return htonl(dest_ip_int ^ src_ip_int) + + def udp_hash(self, dest_port, src_port): + return htons(dest_port ^ src_port) + + def slave_map_hash(self, port, order_ports): + if len(order_ports) == 0: + return None + else: + order_ports = order_ports.split() + return order_ports.index(str(port)) + + def verify_xor_rx(self, unbond_port, bond_port, **slaves): + """ + slaves: + 'active'=[] + 'inactive'=[] + """ + pkt_count = 100 + pkt_orig = {} + pkt_now = {} + + # send to slave ports + pkt_orig = self.get_all_stats(unbond_port, 'tx', bond_port, **slaves) + for slave in slaves['active']: + self.send_packet(self.dut_ports[slave], 64, pkt_count) + pkt_now = self.get_all_stats(unbond_port, 'tx', bond_port, **slaves) + + for key in pkt_now: + for num in [0, 1, 2]: + pkt_now[key][num] -= pkt_orig[key][num] + + for slave in slaves['active']: + self.verify(pkt_now[slave][0] == pkt_count, "Slave have error RX packet in XOR") + for slave in slaves['inactive']: + self.verify(pkt_now[slave][0] == 0, "Slave have error RX packet in XOR") + self.verify(pkt_now[unbond_port][0] == pkt_count * len(slaves['active']), "Unbonded device have error TX packet in XOR") + + def verify_xor_tx(self, unbond_port, bond_port, policy, vlan_tag=False, **slaves): + """ + vlan_tag:False or True + policy:'L2' , 'L23' or 'L34' + slaves: + 'active'=[] + 'inactive'=[] + """ + pkt_count = 100 + pkt_orig = {} + pkt_now = {} + + # send to unbond_port + pkt_orig = self.get_all_stats(unbond_port, 'rx', bond_port, **slaves) + + dest_mac = self.dut.get_mac_address(self.dut_ports[unbond_port]) + dest_ip = "10.239.129.88" + dest_port = 53 + + ether_ip = {} + ether = {} + ip = {} + udp = {} + + ether['dest_mac'] = False + ip['dest_ip'] = dest_ip + udp['dest_port'] = 53 + if vlan_tag: + dot1q = {} + dot1q['vlan'] = random.randint(1, 50) + ether_ip['dot1q'] = dot1q + + ether_ip['ether'] = ether + ether_ip['ip'] = ip + ether_ip['udp'] = udp + + source = [('52:00:00:00:00:00', '10.239.129.65', 61), + ('52:00:00:00:00:01', '10.239.129.66', 62), + ('52:00:00:00:00:02', '10.239.129.67', 63)] + + for src_mac, src_ip, src_port in source: + ether_ip['ether']['src_mac'] = src_mac + ether_ip['ip']['src_ip'] = src_ip + ether_ip['udp']['src_port'] = src_port + self.send_packet(unbond_port, 64, pkt_count, False, **ether_ip) + pkt_now = self.get_all_stats(unbond_port, 'rx', bond_port, **slaves) + + for key in pkt_now: + for num in [0, 1, 2]: + pkt_now[key][num] -= pkt_orig[key][num] + + hash_values = [] + if len(slaves['active']) != 0: + for src_mac, src_ip, src_port in source: + if policy == "L2": + hash_value = self.mac_hash(dest_mac, src_mac) + elif policy == "L23": + hash_value = self.mac_hash(dest_mac, src_mac) ^ self.ipv4_hash(dest_ip, src_ip) + else: + hash_value = self.ipv4_hash(dest_ip, src_ip) ^ self.udp_hash(dest_port, src_port) + + if policy in ("L23", "L34"): + hash_value ^= hash_value >> 16 + hash_value ^= hash_value >> 8 + hash_value = hash_value % len(slaves['active']) + hash_values.append(hash_value) + + order_ports = self.get_bond_active_slaves(bond_port) + for slave in slaves['active']: + slave_map_hash = self.slave_map_hash(slave, order_ports) + self.verify(pkt_now[slave][0] == pkt_count * hash_values.count(slave_map_hash), "XOR load balance transmit error on the link up port") + for slave in slaves['inactive']: + self.verify(pkt_now[slave][0] == 0, "XOR load balance transmit error on the link down port") + + def test_xor_tx(self): + self.launch_app() + bond_port = self.create_bonded_device(2, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + + slaves = {} + slaves['active'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + slaves['inactive'] = [] + + self.verify_xor_tx(self.dut_ports[3], bond_port, "L2", False, **slaves) + + def test_xor_tx_one_slave_down(self): + self.launch_app() + bond_port = self.create_bonded_device(2, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[2], self.dut_ports[1]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "down") + + try: + slaves = {} + slaves['active'] = [self.dut_ports[1], self.dut_ports[2]] + slaves['inactive'] = [self.dut_ports[0]] + + self.verify_xor_tx(self.dut_ports[3], bond_port, "L2", False, **slaves) + finally: + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "up") + + def test_xor_tx_all_slave_down(self): + self.launch_app() + bond_port = self.create_bonded_device(2, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "down") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[1]), "down") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[2]), "down") + + try: + slaves = {} + slaves['active'] = [] + slaves['inactive'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + + self.verify_xor_tx(self.dut_ports[3], bond_port, "L2", False, **slaves) + finally: + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "up") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[1]), "up") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[2]), "up") + + def vlan_strip_and_filter(self, action='off', *ports): + for port_id in ports: + self.dut.send_expect("vlan set strip %s %d" % (action, port_id), "testpmd> ") + self.dut.send_expect("vlan set filter %s %d" % (action, port_id), "testpmd> ") + + def test_xor_l34_forward(self): + self.launch_app() + bond_port = self.create_bonded_device(2, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.set_balance_policy_for_bonding_device(bond_port, "l34") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + + slaves = {} + slaves['active'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + slaves['inactive'] = [] + + self.verify_xor_tx(self.dut_ports[3], bond_port, "L34", False, **slaves) + self.vlan_strip_and_filter('off', self.dut_ports[0], self.dut_ports[1], self.dut_ports[2], self.dut_ports[3], bond_port) + self.verify_xor_tx(self.dut_ports[3], bond_port, "L34", True, **slaves) + + def test_xor_rx(self): + self.launch_app() + bond_port = self.create_bonded_device(2, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + + slaves = {} + slaves['active'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + slaves['inactive'] = [] + + self.verify_xor_rx(self.dut_ports[3], bond_port, **slaves) + + def verify_broadcast_bonded_rx(self, unbond_port, bond_port, **slaves): + """ + slaves: + 'active':[] + 'inactive':[] + """ + pkt_count = 100 + pkt_orig = {} + pkt_now = {} + + pkt_orig = self.get_all_stats(unbond_port, 'tx', bond_port, **slaves) + for slave in slaves['active']: + self.send_packet(slave, 64, pkt_count) + pkt_now = self.get_all_stats(unbond_port, 'tx', bond_port, **slaves) + + for key in pkt_now: + for num in [0, 1, 2]: + pkt_now[key][num] -= pkt_orig[key][num] + + for slave in slaves['active']: + self.verify(pkt_now[slave][0] == pkt_count, "Slave RX packet not correct in mode 3") + for slave in slaves['inactive']: + self.verify(pkt_now[slave][0] == 0, "Slave RX packet not correct in mode 3") + self.verify(pkt_now[unbond_port][0] == pkt_count * len(slaves['active']), + "Unbonded port TX packet not correct in mode 3") + self.verify(pkt_now[bond_port][0] == pkt_count * len(slaves['active']), + "Bonded device RX packet not correct in mode 3") + + def verify_broadcast_bonded_tx(self, unbond_port, bond_port, **slaves): + """ + slaves: + 'actvie':[] + 'inactive':[] + """ + pkt_count = 100 + pkt_orig = {} + pkt_now = {} + + # send to unbonded device + pkt_orig = self.get_all_stats(unbond_port, 'rx', bond_port, **slaves) + self.send_packet(unbond_port, 64, pkt_count) + pkt_now = self.get_all_stats(unbond_port, 'rx', bond_port, **slaves) + + for key in pkt_now: + for num in [0, 1, 2]: + pkt_now[key][num] -= pkt_orig[key][num] + + for slave in slaves['active']: + self.verify(pkt_now[slave][0] == pkt_count, "Slave TX packet not correct in mode 3") + for slave in slaves['inactive']: + self.verify(pkt_now[slave][0] == 0, "Slave TX packet not correct in mode 3") + self.verify(pkt_now[unbond_port][0] == pkt_count, "Unbonded port RX packet not correct in mode 3") + self.verify(pkt_now[bond_port][0] == pkt_count * len(slaves['active']), + "Bonded device TX packet not correct in mode 3") + + def test_broadcast_rx_tx(self): + self.launch_app() + bond_port = self.create_bonded_device(3, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + + slaves = {} + slaves['active'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + slaves['inactive'] = [] + + self.verify_broadcast_bonded_rx(self.dut_ports[3], bond_port, **slaves) + self.verify_broadcast_bonded_tx(self.dut_ports[3], bond_port, **slaves) + + def test_broadcast_tx_one_slave_down(self): + self.launch_app() + bond_port = self.create_bonded_device(3, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "down") + + try: + slaves = {} + slaves['active'] = [self.dut_ports[1], self.dut_ports[2]] + slaves['inactive'] = [self.dut_ports[0]] + + self.verify_broadcast_bonded_tx(self.dut_ports[3], bond_port, **slaves) + finally: + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "up") + + def test_broadcast_tx_all_slave_down(self): + self.launch_app() + bond_port = self.create_bonded_device(3, 0) + self.add_slave_to_bonding_device(bond_port, False, self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]) + self.dut.send_expect("set portlist %d,%d" % (self.dut_ports[3], bond_port), "testpmd> ") + self.start_all_ports() + self.dut.send_expect("start", "testpmd> ") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "down") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[1]), "down") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[2]), "down") + + try: + slaves = {} + slaves['active'] = [] + slaves['inactive'] = [self.dut_ports[0], self.dut_ports[1], self.dut_ports[2]] + + self.verify_broadcast_bonded_tx(self.dut_ports[3], bond_port, **slaves) + finally: + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[0]), "up") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[1]), "up") + self.admin_tester_port(self.tester.get_local_port(self.dut_ports[2]), "up") + + def tear_down(self): + """ + Run after each test case. + """ + self.dut.send_expect("quit", "# ") + + def tear_down_all(self): + """ + Run after each test suite. + """ + pass diff --git a/tests/TestSuite_timer.py b/tests/TestSuite_timer.py new file mode 100644 index 0000000..f144bea --- /dev/null +++ b/tests/TestSuite_timer.py @@ -0,0 +1,86 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test Timer. + +""" + +import dcts +import re +import time + + +from test_case import TestCase + +# +# +# Test class. +# + + +class TestTimer(TestCase): + + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + Run at the start of each test suite. + + + timer prerequistites + """ + out = self.dut.build_dpdk_apps('examples/timer') + + self.verify("Error" not in out, "compilation error 1") + self.verify("No such file" not in out, "compilation error 2") + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_timer_callbacks_verify(self): + """ + Timer callbacks running on targeted cores + """ + + # get the mask for the first core + cores = self.dut.get_core_list('1S/1C/1T') + coreMask = dcts.create_mask(cores) + + # run timer on the background + cmdline = "./examples/timer/build/app/timer -n 1 -c " + coreMask + " &" + + self.dut.send_expect(cmdline, "# ", 1) + time.sleep(15) + out = self.dut.send_expect("killall timer", "# ", 5) + + # verify timer0 + dcts.regexp(out, r'timer0_cb\(\) on lcore (\d+)') + pat = re.compile(r'timer0_cb\(\) on lcore (\d+)') + match = pat.findall(out) + self.verify(match or match[0] == 0, "timer0 error") + + # verify timer1 + pat = re.compile(r'timer1_cb\(\) on lcore (\d+)') + matchlist = sorted(pat.findall(out)) + self.verify(cmp(list(set(matchlist)), cores) == 0, "timer1 error") + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + pass diff --git a/tests/TestSuite_vlan.py b/tests/TestSuite_vlan.py new file mode 100644 index 0000000..11ef94f --- /dev/null +++ b/tests/TestSuite_vlan.py @@ -0,0 +1,182 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test the support of VLAN Offload Features by Poll Mode Drivers. + +""" + +import dcts +import time + + +from test_case import TestCase + +# +# +# Test class. +# + + +class TestVlan(TestCase): + + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + Run at the start of each test suite. + + + Vlan Prerequistites + """ + + # Based on h/w type, choose how many ports to use + ports = self.dut.get_ports(self.nic) + + # Verify that enough ports are available + self.verify(len(ports) >= 2, "Insufficient ports") + + cores = self.dut.get_core_list('1S/2C/2T') + coreMask = dcts.create_mask(cores) + + ports = self.dut.get_ports(self.nic) + global valports + valports = [_ for _ in ports if self.tester.get_local_port(_) != -1] + + portMask = dcts.create_mask(valports[:2]) + + cmd = "./%s/build/app/test-pmd/testpmd -c %s -n 3 -- -i --burst=1 \ + --mbcache=250 --portmask=%s" % (self.target, coreMask, portMask) + + self.dut.send_expect("%s" % cmd, "testpmd> ", 120) + self.dut.send_expect("set verbose 1", "testpmd> ") + out = self.dut.send_expect("set fwd mac", "testpmd> ") + self.dut.send_expect("vlan set strip off %s" % valports[0], "testpmd> ") + self.verify('Set mac packet forwarding mode' in out, "set fwd rxonly error") + + def vlan_send_packet(self, vid, num=1): + """ + Send $num of packet to portid + """ + + port = self.tester.get_local_port(valports[0]) + txItf = self.tester.get_interface(port) + + port = self.tester.get_local_port(valports[1]) + rxItf = self.tester.get_interface(port) + + mac = self.dut.get_mac_address(valports[0]) + + # FIXME send a burst with only num packet + self.tester.scapy_background() + self.tester.scapy_append('p=sniff(iface="%s",count=1,timeout=5)' % rxItf) + self.tester.scapy_append('RESULT=str(p)') + + self.tester.scapy_foreground() + self.tester.scapy_append('sendp([Ether(dst="%s")/Dot1Q(vlan=%s)/IP(len=46)], iface="%s")' % (mac, vid, txItf)) + + self.tester.scapy_execute() + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_vlan_enable_receipt(self): + """ + Enable receipt of VLAN packets + """ + self.dut.send_expect("set promisc all off", "testpmd> ") + self.dut.send_expect("rx_vlan add 1 %s" % valports[0], "testpmd> ") + self.dut.send_expect("start", "testpmd> ", 120) + + self.vlan_send_packet(1) + out = self.tester.scapy_get_result() + self.verify("vlan=1L" in out, "Wrong vlan:" + out) + + self.dut.send_expect("stop", "testpmd> ") + + def test_vlan_disable_receipt(self): + """ + Disable receipt of VLAN packets + """ + + self.dut.send_expect("rx_vlan rm 1 %s" % valports[0], "testpmd> ") + self.dut.send_expect("start", "testpmd> ", 120) + + self.vlan_send_packet(1) + + out = self.tester.scapy_get_result() + self.verify("vlan=1L" not in out, "Wrong vlan:" + out) + + out = self.dut.send_expect("stop", "testpmd> ") + + def test_vlan_strip_config_on(self): + self.dut.send_expect("vlan set strip on %s" % valports[0], "testpmd> ", 20) + self.dut.send_expect("set promisc all off", "testpmd> ", 20) + out = self.dut.send_expect("vlan set strip on %s" % valports[0], "testpmd> ", 20) + self.verify("strip on" in out, "Wrong strip:" + out) + + self.dut.send_expect("start", "testpmd> ", 120) + self.vlan_send_packet(1) + out = self.tester.scapy_get_result() + self.verify("vlan=1L" not in out, "Wrong vlan:" + out) + out = self.dut.send_expect("quit", "#", 120) + + def test_vlan_strip_config_off(self): + self.dut.send_expect("vlan set strip off %s" % valports[0], "testpmd> ", 20) + out = self.dut.send_expect("show port info %s" % valports[0], "testpmd> ", 20) + self.verify("strip off" in out, "Wrong strip:" + out) + self.dut.send_expect("set nbport 2", "testpmd> ") + self.dut.send_expect("start", "testpmd> ", 120) + self.vlan_send_packet(1) + out = self.tester.scapy_get_result() + self.verify("vlan=1L" in out, "Wrong strip vlan:" + out) + out = self.dut.send_expect("stop", "testpmd> ", 120) + + def FAILING_test_vlan_enable_vlan_insertion(self): + """ + Enable VLAN header insertion in transmitted packets + """ + + port = self.tester.get_local_port(valports[0]) + intf = self.tester.get_interface(port) + + self.dut.send_expect("set nbport 2", "testpmd> ") + self.dut.send_expect("tx_vlan set 1 %s" % valports[0], "testpmd> ") + + self.dut.send_expect("set promisc all on", "testpmd> ") + if self.nic == 'hartwell': + self.dut.send_expect("vlan set strip on %s" % valports[0], "testpmd> ") + + self.tester.scapy_background() + self.tester.scapy_append('p = sniff(iface="%s", count=1, timeout=5)' % intf) + self.tester.scapy_append('RESULT=str(p)') + self.tester.scapy_foreground() + + self.tester.scapy_execute() + time.sleep(2) + self.dut.send_expect("start tx_first", "testpmd> ") + time.sleep(2) + + out = self.tester.scapy_get_result() + self.verify("vlan=1L" in out, "Wrong vlan: " + out) + self.dut.send_expect("quit", "# ", 30) + + def tear_down(self): + """ + Run after each test case. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + pass diff --git a/tests/TestSuite_whitelist.py b/tests/TestSuite_whitelist.py new file mode 100644 index 0000000..3ef1756 --- /dev/null +++ b/tests/TestSuite_whitelist.py @@ -0,0 +1,197 @@ +# <COPYRIGHT_TAG> + +""" +DPDK Test suite. + +Test the support of Whitelist Features by Poll Mode Drivers + +""" + +import dcts +import time + + +from test_case import TestCase + +# +# +# Test class. +# + + +class TestWhitelist(TestCase): + + # + # + # + # Test cases. + # + + def set_up_all(self): + """ + Run at the start of each test suite. + Whitelist Prerequistites: + Two Ports + testpmd can normally started + """ + + self.frames_to_send = 1 + + # Based on h/w type, choose how many ports to use + self.dutPorts = self.dut.get_ports(self.nic) + + # Verify that enough ports are available + self.verify(len(self.dutPorts) >= 1, "Insufficient ports") + + cores = self.dut.get_core_list('1S/2C/1T') + coreMask = dcts.create_mask(cores) + + portMask = dcts.create_mask(self.dutPorts[:2]) + + cmd = "./%s/build/app/test-pmd/testpmd -c %s -n 3 -- -i --burst=1 --rxpt=0 \ + --rxht=0 --rxwt=0 --txpt=36 --txht=0 --txwt=0 --txrst=32 --txfreet=32 --rxfreet=64 --mbcache=250 --portmask=%s" % (self.target, coreMask, portMask) + self.dut.send_expect("%s" % cmd, "testpmd> ", 120) + self.dut.send_expect("set verbose 1", "testpmd> ") + + # get dest address from self.target port + out = self.dut.send_expect("show port info %d" % self.dutPorts[0], "testpmd> ") + + self.dest = self.dut.get_mac_address(self.dutPorts[0]) + mac_scanner = r"MAC address: (([\dA-F]{2}:){5}[\dA-F]{2})" + + ret = dcts.regexp(out, mac_scanner) + self.verify(ret is not None, "MAC address not found") + self.verify(cmp(ret.lower(), self.dest) == 0, "MAC address wrong") + + self.max_mac_addr = dcts.regexp(out, "Maximum number of MAC addresses: ([0-9]+)") + + def set_up(self): + """ + Run before each test case. + Nothing to do. + """ + pass + + def whitelist_send_packet(self, portid, destMac="00:11:22:33:44:55"): + """ + Send 1 packet to portid. + """ + + itf = self.tester.get_interface(self.tester.get_local_port(portid)) + + self.tester.scapy_foreground() + self.tester.scapy_append('sendp([Ether(dst="%s", src="52:00:00:00:00:00")], iface="%s", count=%d)' % (destMac, + itf, + self.frames_to_send)) + self.tester.scapy_execute() + + time.sleep(5) + + def test_whitelist_add_remove_mac_address(self): + """ + Add mac address and check packet can received + Remove mac address and check packet can't received + """ + # initialise first port without promiscuous mode + fake_mac_addr = "01:01:01:00:00:00" + portid = self.dutPorts[0] + self.dut.send_expect("set promisc %d off" % portid, "testpmd> ") + + out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ") + pre_rxpkt = dcts.regexp(out, "RX-packets: ([0-9]+)") + + # send one packet with the portid MAC address + self.whitelist_send_packet(portid, self.dest) + out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ") + cur_rxpkt = dcts.regexp(out, "RX-packets: ([0-9]+)") + # check the packet increase + self.verify(int(cur_rxpkt) == int(pre_rxpkt) + self.frames_to_send, + "Packet has not been received on default address") + # send one packet to a different MAC address + # new_mac = self.dut.get_mac_address(portid) + self.whitelist_send_packet(portid, fake_mac_addr) + + pre_rxpkt = cur_rxpkt + out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ") + cur_rxpkt = dcts.regexp(out, "RX-packets: ([0-9]+)") + + # check the packet DO NOT increase + self.verify(int(cur_rxpkt) == int(pre_rxpkt), + "Packet has been received on a new MAC address that has not been added yet") + # add the different MAC address + out = self.dut.send_expect("mac_addr add %d" % portid + " %s" % fake_mac_addr, "testpmd>") + + # send again one packet to a different MAC address + self.whitelist_send_packet(portid, fake_mac_addr) + + pre_rxpkt = cur_rxpkt + out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ") + cur_rxpkt = dcts.regexp(out, "RX-packets: ([0-9]+)") + + # check the packet increase + self.verify(int(cur_rxpkt) == int(pre_rxpkt) + self.frames_to_send, + "Packet has not been received on a new MAC address that has been added to the port") + + # remove the fake MAC address + out = self.dut.send_expect("mac_addr remove %d" % portid + " %s" % fake_mac_addr, "testpmd>") + + # send again one packet to a different MAC address + self.whitelist_send_packet(portid, fake_mac_addr) + + pre_rxpkt = cur_rxpkt + out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ") + cur_rxpkt = dcts.regexp(out, "RX-packets: ([0-9]+)") + + # check the packet increase + self.verify(int(cur_rxpkt) == int(pre_rxpkt), + "Packet has been received on a new MAC address that has been removed from the port") + self.dut.send_expect("stop", "testpmd> ") + + def test_whitelist_invalid_addresses(self): + """ + Invalid operation: + Add NULL MAC should not be added + Remove using MAC will be failed + Add Same MAC twice will be failed + Add more than MAX number will be failed + """ + + portid = self.dutPorts[0] + fake_mac_addr = "00:00:00:00:00:00" + + # add an address with all zeroes to the port (-EINVAL) + out = self.dut.send_expect("mac_addr add %d" % portid + " %s" % fake_mac_addr, "testpmd>") + self.verify("Invalid argument" in out, "Added a NULL MAC address") + + # remove the default MAC address (-EADDRINUSE) + out = self.dut.send_expect("mac_addr remove %d" % portid + " %s" % self.dest, "testpmd>") + self.verify("Address already in use" in out, "default address removed") + + # add same address 2 times + fake_mac_addr = "00:00:00:00:00:01" + out = self.dut.send_expect("mac_addr add %d" % portid + " %s" % fake_mac_addr, "testpmd>") + out = self.dut.send_expect("mac_addr add %d" % portid + " %s" % fake_mac_addr, "testpmd>") + self.verify("error" not in out, "added 2 times the same address with an error") + + # add 1 address more that max number + i = 0 + base_addr = "01:00:00:00:00:" + while i <= int(self.max_mac_addr): + new_addr = base_addr + "%0.2X" % i + out = self.dut.send_expect("mac_addr add %d" % portid + " %s" % new_addr, "testpmd>") + i = i + 1 + + self.verify("No space left on device" in out, "added 1 address more than max MAC addresses") + + def tear_down(self): + """ + Run after each test case. + Nothing to do. + """ + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + self.dut.send_expect("quit", "# ", 10) |