From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by dpdk.org (Postfix) with ESMTP id 6C2CE5A50 for ; Mon, 8 Jun 2015 04:21:47 +0200 (CEST) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga103.fm.intel.com with ESMTP; 07 Jun 2015 19:21:46 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.13,571,1427785200"; d="scan'208";a="722825917" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by fmsmga001.fm.intel.com with ESMTP; 07 Jun 2015 19:21:45 -0700 Received: from shecgisg003.sh.intel.com (shecgisg003.sh.intel.com [10.239.29.90]) by shvmail01.sh.intel.com with ESMTP id t582LhYx032263; Mon, 8 Jun 2015 10:21:43 +0800 Received: from shecgisg003.sh.intel.com (localhost [127.0.0.1]) by shecgisg003.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id t582LfYs005665; Mon, 8 Jun 2015 10:21:43 +0800 Received: (from yliu84x@localhost) by shecgisg003.sh.intel.com (8.13.6/8.13.6/Submit) id t582Lf8e005661; Mon, 8 Jun 2015 10:21:41 +0800 From: Yong Liu To: dts@dpdk.org Date: Mon, 8 Jun 2015 10:21:28 +0800 Message-Id: <1433730088-5601-5-git-send-email-yong.liu@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1433730088-5601-1-git-send-email-yong.liu@intel.com> References: <1433730088-5601-1-git-send-email-yong.liu@intel.com> Subject: [dts] [PATCH 4/4] Add vxlan test suite. X-BeenThere: dts@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: test suite reviews and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 08 Jun 2015 02:21:48 -0000 From: Marvin Liu There're eight cases contained in this suite. 1) test_vxlan_ipv4_detect Check whether FVL card can detect vxlan packets. 2) test_vxlan_ipv6_detect Check whether FVL card can detect vxlan packets contain ipv6 header. 3) test_vxlan_ipv4_checksum_offload Check hardware checksum work fine with vxlan packets. 4) test_vxlan_ipv6_checksum_offload Check hardware checksum work fine with vxlan packets contain ipv6 header. 5) test_tunnel_filter Check FVL tunnel filter can work with vxlan packets. 6) test_tunnel_filter_invalid Check invalid tunnel filter command can normally handled. 7) test_perf_vxlan_tunnelfilter_performance_2ports Performance test of vxlan tunnel filter on FVL. 8) test_perf_vxlan_checksum_performance_2ports Performance test of vxlan hardware chksum offload. Signed-off-by: Marvin Liu diff --git a/tests/TestSuite_vxlan.py b/tests/TestSuite_vxlan.py new file mode 100644 index 0000000..8b7329c --- /dev/null +++ b/tests/TestSuite_vxlan.py @@ -0,0 +1,1101 @@ +""" +DPDK Test suite. + +Test IPv4 fragmentation features in DPDK. + +""" + +import dts +import string +import re +import time +import os +from pmd_output import PmdOutput + +from socket import AF_INET6 +from scapy.utils import struct, socket, wrpcap, rdpcap +from scapy.layers.inet import Ether, IP, TCP, UDP +from scapy.layers.inet6 import IPv6 +from scapy.layers.l2 import Dot1Q +from scapy.layers.vxlan import Vxlan +from scapy.layers.sctp import SCTP, SCTPChunkData +from scapy.sendrecv import sniff +from scapy.config import conf +from scapy.route import * + +from test_case import TestCase +from settings import HEADER_SIZE +from etgen import IxiaPacketGenerator + +# +# +# Test class. +# + +VXLAN_PORT = 4789 +PACKET_LEN = 128 +BIDIRECT = True + + +class VxlanTestConfig(object): + + """ + Module for config/create/transmit vxlan packet + """ + + def __init__(self, test_case, **kwargs): + self.test_case = test_case + self.init() + for name in kwargs: + setattr(self, name, kwargs[name]) + + def init(self): + self.packets_config() + + def packets_config(self): + """ + Default vxlan packet format + """ + self.pcap_file = 'vxlan.pcap' + self.capture_file = 'capture.pcap' + self.outer_mac_src = '00:00:10:00:00:00' + self.outer_mac_dst = '11:22:33:44:55:66' + self.outer_vlan = 'N/A' + self.outer_ip_src = '192.168.1.1' + self.outer_ip_dst = '192.168.1.2' + self.outer_ip_invalid = 0 + self.outer_ip6_src = 'N/A' + self.outer_ip6_dst = 'N/A' + self.outer_ip6_invalid = 0 + self.outer_udp_src = 63 + self.outer_udp_dst = VXLAN_PORT + self.outer_udp_invalid = 0 + self.vni = 1 + self.inner_mac_src = '00:00:20:00:00:00' + self.inner_mac_dst = '00:00:20:00:00:01' + self.inner_vlan = 'N/A' + self.inner_ip_src = '192.168.2.1' + self.inner_ip_dst = '192.168.2.2' + self.inner_ip_invalid = 0 + self.inner_ip6_src = 'N/A' + self.inner_ip6_dst = 'N/A' + self.inner_ip6_invalid = 0 + self.payload_size = 18 + self.inner_l4_type = 'UDP' + self.inner_l4_invalid = 0 + + def packet_type(self): + """ + Return vxlan packet type + """ + if self.outer_udp_dst != VXLAN_PORT: + if self.outer_ip6_src != 'N/A': + return 'PKT_RX_IPV6_HDR' + else: + return 'PKT_RX_IPV4_HDR' + else: + if self.outer_ip6_src != 'N/A': + return 'PKT_RX_TUNNEL_IPV6_HDR' + else: + return 'PKT_RX_TUNNEL_IPV4_HDR' + + def create_pcap(self, scp=True): + """ + Create pcap file and copy it to tester if configured + Return scapy packet object for later usage + """ + if self.inner_l4_type == 'SCTP': + self.inner_payload = SCTPChunkData(data='X' * 16) + else: + self.inner_payload = ("X" * self.payload_size) + + if self.inner_l4_type == 'TCP': + l4_pro = TCP() + elif self.inner_l4_type == 'SCTP': + l4_pro = SCTP() + else: + l4_pro = UDP() + + if self.inner_ip6_src != 'N/A': + inner_l3 = IPv6() + else: + inner_l3 = IP() + + if self.inner_vlan != 'N/A': + inner = Ether() / Dot1Q() / inner_l3 / l4_pro / self.inner_payload + inner[Dot1Q].vlan = self.inner_vlan + else: + inner = Ether() / inner_l3 / l4_pro / self.inner_payload + + if self.inner_ip6_src != 'N/A': + inner[inner_l3.name].src = self.inner_ip6_src + inner[inner_l3.name].dst = self.inner_ip6_dst + else: + inner[inner_l3.name].src = self.inner_ip_src + inner[inner_l3.name].dst = self.inner_ip_dst + + if self.inner_ip_invalid == 1: + inner[inner_l3.name].chksum = 0 + + # when udp checksum is 0, will skip checksum + if self.inner_l4_invalid == 1: + if self.inner_l4_type == 'SCTP': + inner[SCTP].chksum = 0 + else: + inner[self.inner_l4_type].chksum = 1 + + inner[Ether].src = self.inner_mac_src + inner[Ether].dst = self.inner_mac_dst + + if self.outer_ip6_src != 'N/A': + outer_l3 = IPv6() + else: + outer_l3 = IP() + + if self.outer_vlan != 'N/A': + outer = Ether() / Dot1Q() / outer_l3 / UDP() + outer[Dot1Q].vlan = self.outer_vlan + else: + outer = Ether() / outer_l3 / UDP() + + outer[Ether].src = self.outer_mac_src + outer[Ether].dst = self.outer_mac_dst + + if self.outer_ip6_src != 'N/A': + outer[outer_l3.name].src = self.outer_ip6_src + outer[outer_l3.name].dst = self.outer_ip6_dst + else: + outer[outer_l3.name].src = self.outer_ip_src + outer[outer_l3.name].dst = self.outer_ip_dst + + outer[UDP].src = self.outer_udp_src + outer[UDP].dst = self.outer_udp_dst + + if self.outer_ip_invalid == 1: + outer[outer_l3.name].chksum = 0 + # when udp checksum is 0, will skip checksum + if self.outer_udp_invalid == 1: + outer[UDP].chksum = 1 + + if self.outer_udp_dst == VXLAN_PORT: + self.pkt = outer / Vxlan(vni=self.vni) / inner + else: + self.pkt = outer / ("X" * self.payload_size) + + if scp is True: + wrpcap(self.pcap_file, self.pkt) + self.test_case.tester.session.copy_file_to(self.pcap_file) + + return self.pkt + + def get_chksums(self, pcap=None, tester=False): + """ + get chksum values of Outer and Inner packet L3&L4 + Skip outer udp for it will be calculated by software + """ + chk_sums = {} + if pcap is None: + if tester is True: + self.test_case.tester.session.copy_file_from(self.pcap_file) + pkts = rdpcap(self.pcap_file) + else: + if tester is True: + self.test_case.tester.session.copy_file_from(pcap) + pkts = rdpcap(pcap) + + time.sleep(1) + + if pkts[0].guess_payload_class(pkts[0]).name == "IP": + chk_sums['outer_ip'] = hex(pkts[0][IP].chksum) + + if pkts[0].haslayer(Vxlan) == 1: + inner = pkts[0][Vxlan] + if inner.haslayer(IP) == 1: + chk_sums['inner_ip'] = hex(inner[IP].chksum) + if inner[IP].proto == 6: + chk_sums['inner_tcp'] = hex(inner[TCP].chksum) + if inner[IP].proto == 17: + chk_sums['inner_udp'] = hex(inner[UDP].chksum) + if inner[IP].proto == 132: + chk_sums['inner_sctp'] = hex(inner[SCTP].chksum) + elif inner.haslayer(IPv6) == 1: + if inner[IPv6].nh == 6: + chk_sums['inner_tcp'] = hex(inner[TCP].chksum) + if inner[IPv6].nh == 17: + chk_sums['inner_udp'] = hex(inner[UDP].chksum) + # scapy can not get sctp checksum, so extracted manually + if inner[IPv6].nh == 59: + load = str(inner[IPv6].payload) + chk_sums['inner_sctp'] = hex((ord(load[8]) << 24) | + (ord(load[9]) << 16) | + (ord(load[10]) << 8) | + (ord(load[11]))) + + return chk_sums + + def send_pcap(self, iface=""): + """ + Send vxlan pcap file by iface + """ + self.test_case.tester.scapy_append( + 'pcap = rdpcap("%s")' % self.pcap_file) + self.test_case.tester.scapy_append( + 'sendp(pcap, iface="%s")' % iface) + self.test_case.tester.scapy_execute() + + def pcap_len(self): + """ + Return length of pcap packet, will plus 4 bytes crc + """ + # add four bytes crc + return len(self.pkt) + 4 + + +class TestVxlan(TestCase, IxiaPacketGenerator): + + def set_up_all(self): + """ + vxlan Prerequisites + """ + # this feature only enable in FVL now + self.verify(self.nic in ["fortville_eagle", "fortville_spirit", + "fortville_spirit_single"], + "Vxlan Only supported by Fortville") + # Based on h/w type, choose how many ports to use + ports = self.dut.get_ports() + + # update IxiaPacketGenerator function by local + self.tester.extend_external_packet_generator(TestVxlan, self) + + # Verify that enough ports are available + self.verify(len(ports) >= 2, "Insufficient ports for testing") + global valports + valports = [_ for _ in ports if self.tester.get_local_port(_) != -1] + + self.portMask = dts.create_mask(valports[:2]) + + # Verify that enough threads are available + netdev = self.dut.ports_info[ports[0]]['port'] + self.ports_socket = netdev.socket + cores = self.dut.get_core_list("1S/5C/2T", socket=self.ports_socket) + self.verify(cores is not None, "Insufficient cores for speed testing") + self.coremask = dts.create_mask(cores) + + # start testpmd + self.pmdout = PmdOutput(self.dut) + + # init port config + self.dut_port = valports[0] + self.dut_port_mac = self.dut.get_mac_address(self.dut_port) + tester_port = self.tester.get_local_port(self.dut_port) + self.tester_iface = self.tester.get_interface(tester_port) + self.recv_port = valports[1] + tester_recv_port = self.tester.get_local_port(self.recv_port) + self.recv_iface = self.tester.get_interface(tester_recv_port) + + # invalid parameter + self.invalid_mac = "00:00:00:00:01" + self.invalid_ip = "192.168.1.256" + self.invalid_vlan = 4097 + self.invalid_queue = 64 + + # vxlan payload length for performance test + # inner packet not contain crc, should need add four + self.vxlan_payload = PACKET_LEN - HEADER_SIZE['eth'] - \ + HEADER_SIZE['ip'] - HEADER_SIZE['udp'] - \ + HEADER_SIZE['vxlan'] - HEADER_SIZE['eth'] - \ + HEADER_SIZE['ip'] - HEADER_SIZE['udp'] + 4 + + # performance test cycle + self.test_cycles = [ + {'cores': '1S/1C/1T', 'Mpps': {}, 'pct': {}}, + {'cores': '1S/1C/2T', 'Mpps': {}, 'pct': {}}, + {'cores': '1S/2C/1T', 'Mpps': {}, 'pct': {}} + ] + + self.cal_type = [ + {'Type': 'SOFTWARE ALL', 'csum': []}, + {'Type': 'HW L3', 'csum': ['ip']}, + {'Type': 'HW L4', 'csum': ['udp']}, + {'Type': 'HW L3&L4', 'csum': ['ip', 'udp']}, + ] + + self.table_header = ['Calculate Type'] + for test_cycle in self.test_cycles: + self.table_header.append("%s Mpps" % test_cycle['cores']) + self.table_header.append("% linerate") + + # tunnel filter performance test + self.default_vlan = 1 + self.tunnel_multiqueue = 2 + self.tunnel_header = [ + 'Packet', 'Filter', 'Queue', 'Mpps', '% linerate'] + self.tunnel_perf = [ + {'Packet': 'Normal', 'tunnel_filter': 'None', + 'recvqueue': 'Single', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'None', + 'recvqueue': 'Single', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'imac-ivlan', + 'recvqueue': 'Single', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'imac-ivlan-tenid', + 'recvqueue': 'Single', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'imac-tenid', + 'recvqueue': 'Single', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'imac', + 'recvqueue': 'Single', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'omac-imac-tenid', + 'recvqueue': 'Single', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'None', + 'recvqueue': 'Multi', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'imac-ivlan', + 'recvqueue': 'Multi', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'imac-ivlan-tenid', + 'recvqueue': 'Multi', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'imac-tenid', + 'recvqueue': 'Multi', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': 'imac', + 'recvqueue': 'Multi', 'Mpps': {}, 'pct': {}}, + {'Packet': 'Vxlan', 'tunnel_filter': + 'omac-imac-tenid', 'recvqueue': 'Multi'} + ] + + def send_and_detect(self, **kwargs): + """ + send vxlan packet and check whether testpmd detect the correct + packet type + """ + pmd_temp = "./%(TARGET)s/app/testpmd -c %(COREMASK)s -n " + \ + "%(CHANNEL)d -- -i --disable-rss --rxq=4 --txq=4" + \ + " --nb-cores=8 --portmask=%(PORT)s --txqflags=0x0" + pmd_cmd = pmd_temp % {'TARGET': self.target, + 'COREMASK': self.coremask, + 'CHANNEL': self.dut.get_memory_channels(), + 'PORT': self.portMask} + self.dut.send_expect(pmd_cmd, "testpmd>", 30) + + self.dut.send_expect("set fwd rxonly", "testpmd>", 10) + self.dut.send_expect("set verbose 1", "testpmd>", 10) + self.enable_vxlan(self.dut_port) + self.enable_vxlan(self.recv_port) + + arg_str = "" + for arg in kwargs: + arg_str += "[%s = %s]" % (arg, kwargs[arg]) + + # create pcap file with supplied arguments + self.logger.info("send vxlan pkts %s" % arg_str) + config = VxlanTestConfig(self, **kwargs) + # now cloud filter will default enable L2 mac filter, so dst mac must + # be same + config.outer_mac_dst = self.dut_port_mac + config.create_pcap() + config.send_pcap(self.tester_iface) + + # check whether detect vxlan type + out = self.dut.send_expect("start", "testpmd>", 10) + self.verify(config.packet_type() in out, "Vxlan Packet not detected") + out = self.dut.send_expect("stop", "testpmd>", 10) + self.dut.send_expect("quit", "#", 10) + + def increment_ip_address(self, addr): + """ + Returns the IP address from a given one, like + 192.168.1.1 ->192.168.1.2 + If disable ip hw chksum, csum routine will increase ip + """ + ip2int = lambda ipstr: struct.unpack('!I', socket.inet_aton(ipstr))[0] + x = ip2int(addr) + int2ip = lambda n: socket.inet_ntoa(struct.pack('!I', n)) + return int2ip(x + 1) + + def increment_ipv6_address(self, addr): + """ + Returns the IP address from a given one, like + FE80:0:0:0:0:0:0:0 -> FE80::1 + csum routine will increase ip + """ + ipv6addr = struct.unpack('!8H', socket.inet_pton(AF_INET6, addr)) + addr = list(ipv6addr) + addr[7] += 1 + ipv6 = socket.inet_ntop(AF_INET6, struct.pack( + '!8H', addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], + addr[6], addr[7])) + return ipv6 + + def send_and_check(self, **kwargs): + """ + send vxlan packet and check whether receive packet with correct + checksum + """ + # create pcap file with supplied arguments + args = {} + for arg in kwargs: + if "invalid" not in arg: + args[arg] = kwargs[arg] + + config = VxlanTestConfig(self, **args) + # now cloud filter will default enable L2 mac filter, so dst mac must + # be same + config.outer_mac_dst = self.dut_port_mac + # csum function will auto add outer ipv src address + if config.outer_ip6_src != "N/A": + config.outer_ip6_src = self.increment_ipv6_address( + config.outer_ip6_src) + else: + config.outer_ip_src = self.increment_ip_address( + config.outer_ip_src) + + # csum function will auto add vxlan inner ipv src address + if config.outer_udp_dst == VXLAN_PORT: + if config.inner_ip6_src != "N/A": + config.inner_ip6_src = self.increment_ipv6_address( + config.inner_ip6_src) + else: + config.inner_ip_src = self.increment_ip_address( + config.inner_ip_src) + + # extract the checksum value of vxlan packet + config.create_pcap() + chksums_ref = config.get_chksums() + self.logger.info("chksums_ref" + str(chksums_ref)) + + # start testpmd with 2queue/1port + pmd_temp = "./%(TARGET)s/app/testpmd -c %(COREMASK)s -n " + \ + "%(CHANNEL)d -- -i --disable-rss --rxq=4 --txq=4" + \ + " --nb-cores=8 --portmask=%(PORT)s --txqflags=0x0" + pmd_cmd = pmd_temp % {'TARGET': self.target, + 'COREMASK': self.coremask, + 'CHANNEL': self.dut.get_memory_channels(), + 'PORT': self.portMask} + self.dut.send_expect(pmd_cmd, "testpmd>", 30) + + # enable tx checksum offload + self.dut.send_expect("set fwd csum", "testpmd>", 10) + self.csum_set_type('ip', self.dut_port) + self.csum_set_type('outer-ip', self.dut_port) + self.csum_set_type('udp', self.dut_port) + self.csum_set_type('tcp', self.dut_port) + self.csum_set_type('sctp', self.dut_port) + self.csum_set_type('ip', self.recv_port) + self.csum_set_type('outer-ip', self.recv_port) + self.csum_set_type('udp', self.recv_port) + self.csum_set_type('tcp', self.recv_port) + self.csum_set_type('sctp', self.recv_port) + self.dut.send_expect("csum parse_tunnel on %d" % + self.dut_port, "testpmd>", 10) + self.dut.send_expect("csum parse_tunnel on %d" % + self.recv_port, "testpmd>", 10) + + self.enable_vxlan(self.dut_port) + self.enable_vxlan(self.recv_port) + + # log the vxlan format + arg_str = "" + for arg in kwargs: + arg_str += "[%s = %s]" % (arg, kwargs[arg]) + + self.logger.info("vxlan packet %s" % arg_str) + + out = self.dut.send_expect("start", "testpmd>", 10) + + # create pcap file with supplied arguments + config = VxlanTestConfig(self, **kwargs) + config.outer_mac_dst = self.dut_port_mac + config.create_pcap() + + # remove tempory files + self.tester.send_expect("rm -rf /root/%s" % config.capture_file, "# ") + # save the capture packet into pcap format + self.tester.scapy_background() + self.tester.scapy_append( + 'p=sniff(iface="%s",count=1,timeout=5)' % self.recv_iface) + self.tester.scapy_append( + 'wrpcap(\"/root/%s\", p)' % config.capture_file) + self.tester.scapy_foreground() + + config.send_pcap(self.tester_iface) + time.sleep(5) + + # extract the checksum offload from saved pcap file + chksums = config.get_chksums(pcap=config.capture_file, tester=True) + os.remove(config.capture_file) + self.logger.info("chksums" + str(chksums)) + + out = self.dut.send_expect("stop", "testpmd>", 10) + + # verify detected l4 invalid checksum + if "inner_l4_invalid" in kwargs and config.inner_l4_type is not 'UDP': + self.verify(self.pmdout.get_pmd_value("Bad-l4csum:", out) + == 1, "Failed to count inner l4 chksum error") + + # verify detected l3 invalid checksum + if "inner_ip_invalid" in kwargs: + self.verify(self.pmdout.get_pmd_value("Bad-ipcsum:", out) + == 1, "Failed to count inner ip chksum error") + + self.dut.send_expect("quit", "#", 10) + + # verify saved pcap checksum same to expected checksum + for key in chksums_ref: + self.verify(chksums[key] == chksums_ref[ + key], "%s not matched to %s" % (key, chksums_ref[key])) + + def filter_and_check(self, filter_type="imac-ivlan", queue_id=3, + vlan=False, remove=False): + """ + send vxlan packet and check whether receive packet in assigned queue + """ + pmd_temp = "./%(TARGET)s/app/testpmd -c %(COREMASK)s -n " + \ + "%(CHANNEL)d -- -i --disable-rss --rxq=4 --txq=4" + \ + " --nb-cores=8 --portmask=%(PORT)s --txqflags=0x0" + pmd_cmd = pmd_temp % {'TARGET': self.target, + 'COREMASK': self.coremask, + 'CHANNEL': self.dut.get_memory_channels(), + 'PORT': self.portMask} + self.dut.send_expect(pmd_cmd, "testpmd>", 30) + + self.dut.send_expect("set fwd rxonly", "testpmd>", 10) + self.dut.send_expect("set verbose 1", "testpmd>", 10) + self.enable_vxlan(self.dut_port) + self.enable_vxlan(self.recv_port) + + if vlan is not False: + config = VxlanTestConfig(self, inner_vlan=vlan) + vlan_id = vlan + else: + config = VxlanTestConfig(self) + vlan_id = 1 + + # now cloud filter will default enable L2 mac filter, so dst mac must + # be same + config.outer_mac_dst = self.dut_port_mac + + args = [self.dut_port, config.outer_mac_dst, config.inner_mac_dst, + config.inner_ip_dst, vlan_id, filter_type, config.vni, + queue_id] + + self.tunnel_filter_add(*args) + + # invalid case request to remove tunnel filter + if remove is True: + queue_id = 0 + args = [self.dut_port, config.outer_mac_dst, config.inner_mac_dst, + config.inner_ip_dst, vlan_id, filter_type, config.vni, + queue_id] + self.tunnel_filter_del(*args) + + # send vxlan packet + config.create_pcap() + config.send_pcap(self.tester_iface) + out = self.dut.send_expect("start", "testpmd>", 10) + + queue = -1 + pattern = re.compile("VNI = (\d) - Receive queue=0x(\d)") + m = pattern.search(out) + if m is not None: + queue = m.group(2) + + # verify received in expected queue + self.verify(queue_id == int(queue), "invalid receive queue") + + self.dut.send_expect("stop", "testpmd>", 10) + self.dut.send_expect("quit", "#", 10) + + def test_vxlan_ipv4_detect(self): + """ + verify vxlan packet detection + """ + # check normal packet + self.send_and_detect(outer_udp_dst=1234) + # check vxlan + UDP inner packet + self.send_and_detect(inner_l4_type='UDP') + # check vxlan + TCP inner packet + self.send_and_detect(inner_l4_type='TCP') + # check vxlan + SCTP inner packet + self.send_and_detect(inner_l4_type='SCTP') + # check vxlan + vlan inner packet + self.send_and_detect(outer_vlan=1) + # check vlan vxlan + vlan inner packet + self.send_and_detect(outer_vlan=1, inner_vlan=1) + + def test_vxlan_ipv6_detect(self): + """ + verify vxlan packet detection with ipv6 header + """ + # check normal ipv6 packet + self.send_and_detect(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + outer_udp_dst=1234) + # check ipv6 vxlan + UDP inner packet + self.send_and_detect(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_type='UDP') + # check ipv6 vxlan + TCP inner packet + self.send_and_detect(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_type='TCP') + # check ipv6 vxlan + SCTP inner packet + self.send_and_detect(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_type='SCTP') + + def test_vxlan_ipv4_checksum_offload(self): + """ + verify vxlan packet checksum offload + """ + # check normal packet + ip checksum invalid + self.send_and_check(outer_ip_invalid=1, outer_udp_dst=1234) + # check vxlan packet + inner ip checksum invalid + self.send_and_check(inner_ip_invalid=1) + # check vxlan packet + outer ip checksum invalid + self.send_and_check(outer_ip_invalid=1) + # check vxlan packet + outer ip + inner ip checksum invalid + self.send_and_check(outer_ip_invalid=1, inner_ip_invalid=1) + # check vxlan packet + inner udp checksum invalid + self.send_and_check(inner_l4_invalid=1) + # check vxlan packet + inner tcp checksum invalid + self.send_and_check(inner_l4_invalid=1, inner_l4_type='TCP') + # check vxlan packet + inner sctp checksum invalid + self.send_and_check(inner_l4_invalid=1, inner_l4_type='SCTP') + # check vlan vxlan packet + outer ip checksum invalid + self.send_and_check(outer_vlan=1, outer_ip_invalid=1) + # check vlan vxlan packet + inner ip checksum invalid + self.send_and_check(outer_vlan=1, inner_ip_invalid=1) + # check vlan vxlan packet + outer&inner ip checksum invalid + self.send_and_check( + outer_vlan=1, outer_ip_invalid=1, inner_ip_invalid=1) + # check vlan vxlan packet + inner vlan + outer ip checksum invalid + self.send_and_check(outer_vlan=1, inner_vlan=1, outer_ip_invalid=1) + # check vlan vxlan packet + inner vlan + inner ip checksum invalid + self.send_and_check(outer_vlan=1, inner_vlan=1, inner_ip_invalid=1) + # check vlan vxlan packet + inner vlan + outer&inner ip checksum + # invalid + self.send_and_check( + outer_vlan=1, inner_vlan=1, outer_ip_invalid=1, inner_ip_invalid=1) + # check vlan vxlan packet + inner vlan + inner udp checksum invalid + self.send_and_check( + outer_vlan=1, inner_l4_invalid=1, inner_l4_type='UDP') + # check vlan vxlan packet + inner vlan + inner tcp checksum invalid + self.send_and_check( + outer_vlan=1, inner_l4_invalid=1, inner_l4_type='TCP') + # check vlan vxlan packet + inner vlan + inner sctp checksum invalid + self.send_and_check( + outer_vlan=1, inner_l4_invalid=1, inner_l4_type='SCTP') + + def test_vxlan_ipv6_checksum_offload(self): + """ + verify vxlan packet checksum offload with ipv6 header + not support ipv6 + sctp + """ + # check normal ipv6 packet + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1") + # check normal ipv6 packet + ip checksum invalid + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + outer_udp_dst=1234) + # check ipv6 vxlan packet + inner ip checksum invalid + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_ip_invalid=1) + # check ipv6 vxlan packet + inner udp checksum invalid + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_invalid=1, inner_l4_type='UDP') + # check ipv6 vxlan packet + inner udp checksum invalid + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_invalid=1, inner_l4_type='UDP') + # check ipv6 vxlan packet + inner tcp checksum invalid + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_invalid=1, inner_l4_type='TCP') + # check ipv6 vlan vxlan packet + inner udp checksum invalid + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_invalid=1, inner_l4_type='UDP', + outer_vlan=1) + # check ipv6 vlan vxlan packet + inner tcp checksum invalid + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_invalid=1, inner_l4_type='TCP', + outer_vlan=1) + # check ipv6 vlan vxlan packet + vlan + inner udp checksum invalid + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_invalid=1, inner_l4_type='UDP', + outer_vlan=1, inner_vlan=1) + # check ipv6 vlan vxlan packet + vlan + inner tcp checksum invalid + self.send_and_check(outer_ip6_src="FE80:0:0:0:0:0:0:0", + outer_ip6_dst="FE80:0:0:0:0:0:0:1", + inner_l4_invalid=1, inner_l4_type='TCP', + outer_vlan=1, inner_vlan=1) + + def test_tunnel_filter(self): + """ + verify tunnel filter feature + """ + # check inner mac + inner vlan filter can work + self.filter_and_check(filter_type="imac-ivlan", vlan=1) + # check inner mac + inner vlan + tunnel id filter can work + self.filter_and_check(filter_type="imac-ivlan-tenid", vlan=1) + # check inner mac + tunnel id filter can work + self.filter_and_check(filter_type="imac-tenid") + # check inner mac filter can work + self.filter_and_check(filter_type="imac") + # check outer mac + inner mac + tunnel id filter can work + self.filter_and_check(filter_type="omac-imac-tenid") + # iip not supported by now + # self.filter_and_check(filter_type="iip") + + def test_tunnel_filter_invalid(self): + """ + verify tunnel filter parameter check function + """ + # invalid parameter + vlan_id = 1 + filter_type = 'omac-imac-tenid' + queue_id = 3 + + self.filter_and_check(filter_type="imac", remove=True) + config = VxlanTestConfig(self) + config.outer_mac_dst = self.dut_port_mac + + pmd_temp = "./%(TARGET)s/app/testpmd -c %(COREMASK)s -n " + \ + "%(CHANNEL)d -- -i --disable-rss --rxq=4 --txq=4" + \ + " --nb-cores=8 --portmask=%(PORT)s --txqflags=0x0" + pmd_cmd = pmd_temp % {'TARGET': self.target, + 'COREMASK': self.coremask, + 'CHANNEL': self.dut.get_memory_channels(), + 'PORT': self.portMask} + self.dut.send_expect(pmd_cmd, "testpmd>", 30) + + self.enable_vxlan(self.dut_port) + self.enable_vxlan(self.recv_port) + args = [self.dut_port, config.outer_mac_dst, self.invalid_mac, + config.inner_ip_dst, vlan_id, filter_type, config.vni, + queue_id] + out = self.tunnel_filter_add(*args) + self.verify("Bad arguments" in out, "Failed to detect invalid mac") + args = [self.dut_port, config.outer_mac_dst, config.inner_mac_dst, + self.invalid_ip, vlan_id, filter_type, config.vni, queue_id] + out = self.tunnel_filter_add(*args) + self.verify("Bad arguments" in out, "Failed to detect invalid ip") + args = [self.dut_port, config.outer_mac_dst, config.inner_mac_dst, + config.inner_ip_dst, self.invalid_vlan, filter_type, + config.vni, queue_id] + out = self.tunnel_filter_add(*args) + self.verify("Input/output error" in out, + "Failed to detect invalid vlan") + args = [self.dut_port, config.outer_mac_dst, config.inner_mac_dst, + config.inner_ip_dst, vlan_id, filter_type, config.vni, + self.invalid_queue] + out = self.tunnel_filter_add(*args) + self.verify("Input/output error" in out, + "Failed to detect invalid queue") + + self.dut.send_expect("stop", "testpmd>", 10) + self.dut.send_expect("quit", "#", 10) + + def config_tunnelfilter(self, dut_port, recv_port, perf_config, pcapfile): + pkts = [] + config = VxlanTestConfig(self, payload_size=self.vxlan_payload - 4) + config.inner_vlan = self.default_vlan + config.outer_mac_dst = self.dut.get_mac_address(dut_port) + config.pcap_file = pcapfile + + tun_filter = perf_config['tunnel_filter'] + recv_queue = perf_config['recvqueue'] + # there's known bug that if enable vxlan, rss will be disabled + if tun_filter == "None" and recv_queue == 'Multi': + print dts.RED("RSS and Tunel filter can't enable in the same time") + else: + self.enable_vxlan(dut_port) + + if tun_filter != 'None': + args = [self.dut_port, config.outer_mac_dst, + config.inner_mac_dst, config.inner_ip_dst, + config.inner_vlan, tun_filter, + config.vni, 0] + self.tunnel_filter_add(*args) + + if perf_config['Packet'] == 'Normal': + config.outer_udp_dst = 63 + config.outer_mac_dst = self.dut.get_mac_address(dut_port) + config.payload_size = PACKET_LEN - \ + HEADER_SIZE['eth'] - HEADER_SIZE['ip'] - HEADER_SIZE['udp'] + + # add default pkt into pkt list + pkt = config.create_pcap(scp=False) + pkts.append(pkt) + + # add other pkts into pkt list when enable multi receive queues + if recv_queue == 'Multi' and tun_filter != 'None': + for queue in range(self.tunnel_multiqueue - 1): + if 'imac' in tun_filter: + config.inner_mac_dst = "00:00:20:00:00:0%d" % ( + queue + 2) + if 'ivlan' in tun_filter: + config.inner_vlan = (queue + 2) + if 'tenid' in tun_filter: + config.vni = (queue + 2) + + # add tunnel filter the same as pkt + pkt = config.create_pcap(scp=False) + pkts.append(pkt) + + args = [dut_port, config.outer_mac_dst, + config.inner_mac_dst, config.inner_ip_dst, + config.inner_vlan, tun_filter, + config.vni, (queue + 1)] + self.tunnel_filter_add(*args) + + # save pkt list into pcap file + wrpcap(config.pcap_file, pkts) + self.tester.session.copy_file_to(config.pcap_file) + + def ip_random(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 -destIpMask "255.255.0.0" ') + self.add_tcl_cmd('ip config -destIpAddrMode ipRandom') + self.add_tcl_cmd('ip config -destIpAddrRepeatCount 65536') + 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 test_perf_vxlan_tunnelfilter_performance_2ports(self): + dts.results_table_add_header(self.tunnel_header) + core_list = self.dut.get_core_list( + '1S/%dC/1T' % (self.tunnel_multiqueue * 2 + 1), + socket=self.ports_socket) + core_mask = dts.create_mask(core_list) + + pmd_temp = "./%(TARGET)s/app/testpmd -c %(COREMASK)s -n " + \ + "%(CHANNEL)d -- -i --disable-rss --rxq=2 --txq=2" + \ + " --nb-cores=4 --portmask=%(PORT)s --txqflags=0x0" + + for perf_config in self.tunnel_perf: + tun_filter = perf_config['tunnel_filter'] + recv_queue = perf_config['recvqueue'] + print dts.GREEN("Measure tunnel performance of [%s %s %s]" + % (perf_config['Packet'], tun_filter, recv_queue)) + + if tun_filter == "None" and recv_queue == "Multi": + pmd_temp = "./%(TARGET)s/app/testpmd -c %(COREMASK)s -n " + \ + "%(CHANNEL)d -- -i --rss-udp --rxq=2 --txq=2" + \ + " --nb-cores=4 --portmask=%(PORT)s --txqflags=0x0" + + pmd_cmd = pmd_temp % {'TARGET': self.target, + 'COREMASK': core_mask, + 'CHANNEL': self.dut.get_memory_channels(), + 'PORT': self.portMask} + self.dut.send_expect(pmd_cmd, "testpmd> ", 100) + + # config flow + self.config_tunnelfilter( + self.dut_port, self.recv_port, perf_config, "flow1.pcap") + # config the flows + tgen_input = [] + tgen_input.append((self.tester.get_local_port(self.dut_port), + self.tester.get_local_port(self.recv_port), + "flow1.pcap")) + + if BIDIRECT: + self.config_tunnelfilter( + self.recv_port, self.dut_port, perf_config, "flow2.pcap") + tgen_input.append((self.tester.get_local_port(self.recv_port), + self.tester.get_local_port(self.dut_port), + "flow2.pcap")) + + self.dut.send_expect("set fwd io", "testpmd>", 10) + self.dut.send_expect("start", "testpmd>", 10) + + if BIDIRECT: + wirespeed = self.wirespeed(self.nic, PACKET_LEN, 2) + else: + wirespeed = self.wirespeed(self.nic, PACKET_LEN, 1) + + if recv_queue == 'Multi' and tun_filter == "None": + ip_ori = self.ip + self.ip = self.ip_random + + # run traffic generator + _, pps = self.tester.traffic_generator_throughput(tgen_input) + + if recv_queue == 'Multi' and tun_filter == "None": + self.ip = ip_ori + + pps /= 1000000.0 + perf_config['Mpps'] = pps + perf_config['pct'] = pps * 100 / wirespeed + + out = self.dut.send_expect("stop", "testpmd>", 10) + self.dut.send_expect("quit", "# ", 10) + + # verify every queue work fine + if recv_queue == 'Multi': + for queue in range(self.tunnel_multiqueue): + self.verify("Queue= %d -> TX Port" + % (queue) in out, + "Queue %d no traffic" % queue) + + table_row = [perf_config['Packet'], tun_filter, recv_queue, + perf_config['Mpps'], perf_config['pct']] + + dts.results_table_add_row(table_row) + + dts.results_table_print() + + def test_perf_vxlan_checksum_performance_2ports(self): + config = VxlanTestConfig(self, payload_size=self.vxlan_payload) + config.outer_mac_dst = self.dut.get_mac_address(self.dut_port) + config.pcap_file = "vxlan1.pcap" + config.create_pcap() + if BIDIRECT: + config.outer_mac_dst = self.dut.get_mac_address(self.recv_port) + config.pcap_file = "vxlan2.pcap" + config.create_pcap() + + all_cores_mask = dts.create_mask(self.dut.get_core_list("all")) + # configure flows + tgen_input = [] + tgen_input.append((self.tester.get_local_port(self.dut_port), + self.tester.get_local_port(self.recv_port), + "vxlan1.pcap")) + if BIDIRECT: + tgen_input.append((self.tester.get_local_port(self.recv_port), + self.tester.get_local_port(self.dut_port), + "vxlan2.pcap")) + + # socket/core/thread + for test_cycle in self.test_cycles: + core_config = test_cycle['cores'] + + # take care the corelist when enable numa + core_list = self.dut.get_core_list(core_config, + socket=self.ports_socket) + + core_mask = dts.create_mask(core_list) + + cmd_temp = "./%(TARGET)s/app/testpmd -c %(CORE)s " + \ + "-n %(CHANNEL)d -- -i --disable-rss --coremask=" + \ + "%(COREMASK)s --portmask=%(PORTMASK)s" + cmd = cmd_temp % {'TARGET': self.target, + 'CORE': all_cores_mask, + 'COREMASK': core_mask, + 'CHANNEL': self.dut.get_memory_channels(), + 'PORTMASK': self.portMask} + + self.dut.send_expect(cmd, "testpmd> ", 100) + self.dut.send_expect("set fwd csum", "testpmd>", 10) + self.dut.send_expect("csum parse_tunnel on %d" % + self.dut_port, "testpmd>", 10) + self.dut.send_expect("csum parse_tunnel on %d" % + self.recv_port, "testpmd>", 10) + self.enable_vxlan(self.dut_port) + self.enable_vxlan(self.recv_port) + + # different calculate type + for cal in self.cal_type: + print dts.GREEN("Measure checksum performance of [%s %s]" + % (test_cycle['cores'], + cal['csum'])) + for pro in cal['csum']: + self.csum_set_type(pro, self.dut_port) + self.csum_set_type(pro, self.recv_port) + + self.dut.send_expect("start", "testpmd>", 10) + + frame_size = config.pcap_len() + if BIDIRECT: + wirespeed = self.wirespeed(self.nic, frame_size, 2) + else: + wirespeed = self.wirespeed(self.nic, frame_size, 1) + # run traffic generator + _, pps = self.tester.traffic_generator_throughput(tgen_input) + + pps /= 1000000.0 + test_cycle['Mpps'][cal['Type']] = pps + test_cycle['pct'][cal['Type']] = pps * 100 / wirespeed + + self.dut.send_expect("stop", "testpmd>", 10) + + self.dut.send_expect("quit", "# ", 10) + + dts.results_table_add_header(self.table_header) + + # save the results + for cal in self.cal_type: + table_row = [cal['Type']] + for test_cycle in self.test_cycles: + table_row.append(test_cycle['Mpps'][cal['Type']]) + table_row.append(test_cycle['pct'][cal['Type']]) + + dts.results_table_add_row(table_row) + + dts.results_table_print() + + def enable_vxlan(self, port): + self.dut.send_expect("rx_vxlan_port add %d %d" + % (VXLAN_PORT, port), + "testpmd>", 10) + + def csum_set_type(self, proto, port): + out = self.dut.send_expect("csum set %s hw %d" % (proto, port), + "testpmd>", 10) + self.verify("Bad arguments" not in out, "Failed to set vxlan csum") + self.verify("error" not in out, "Failed to set vxlan csum") + + def tunnel_filter_add(self, *args): + # tunnel_filter add port_id outer_mac inner_mac ip inner_vlan + # tunnel_type(vxlan) + # filter_type + # (imac-ivlan|imac-ivlan-tenid|imac-tenid|imac|omac-imac-tenid|iip) + # tenant_id queue_num + out = self.dut.send_expect("tunnel_filter add %d " % args[0] + + "%s %s %s " % (args[1], args[2], args[3]) + + "%d vxlan %s " % (args[4], args[5]) + + "%d %d" % (args[6], args[7]), + "testpmd>", 10) + self.verify("Bad arguments" not in out, "Failed to add tunnel filter") + self.verify("error" not in out, "Failed to add tunnel filter") + return out + + def tunnel_filter_del(self, *args): + out = self.dut.send_expect("tunnel_filter rm %d " % args[0] + + "%s %s %s" % (args[1], args[2], args[3]) + + "%d vxlan %s " % (args[4], args[5]) + + "%d %d" % (args[6], args[7]), + "testpmd>", 10) + self.verify("Bad arguments" not in out, + "Failed to remove tunnel filter") + self.verify("error" not in out, "Failed to remove tunnel filter") + return out + + def set_up(self): + """ + Run before each test case. + """ + pass + + def tear_down(self): + """ + Run after each test case. + """ + self.dut.kill_all() + + def tear_down_all(self): + """ + Run after each test suite. + """ + pass -- 1.9.3