From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id 4812EC1EE for ; Wed, 6 Jun 2018 07:33:23 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 05 Jun 2018 22:33:22 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,482,1520924400"; d="scan'208";a="47108506" Received: from shecgisg006.sh.intel.com ([10.239.39.68]) by orsmga008.jf.intel.com with ESMTP; 05 Jun 2018 22:33:21 -0700 Received: from shecgisg006.sh.intel.com (localhost [127.0.0.1]) by shecgisg006.sh.intel.com with ESMTP id w565XKVZ022126; Wed, 6 Jun 2018 13:33:20 +0800 Received: (from yufengmx@localhost) by shecgisg006.sh.intel.com with œ id w565XKSk022122; Wed, 6 Jun 2018 13:33:20 +0800 From: yufengx.mo@intel.com To: dts@dpdk.org Cc: yufengmx Date: Wed, 6 Jun 2018 13:33:20 +0800 Message-Id: <1528263200-21939-3-git-send-email-yufengx.mo@intel.com> X-Mailer: git-send-email 1.7.0.7 In-Reply-To: <1528263200-21939-1-git-send-email-yufengx.mo@intel.com> References: <1528263200-21939-1-git-send-email-yufengx.mo@intel.com> Subject: [dts] [PATCH V1 2/2] packet_capture: upload automation script 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: Wed, 06 Jun 2018 05:33:24 -0000 From: yufengmx Packet capture framework feature support packet capturing on dpdk ethernet devices. DPDK provides dpdk-pdump tool under app/pdump directory for packet capturing on dpdk. Signed-off-by: yufengmx --- tests/TestSuite_packet_capture.py | 892 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 892 insertions(+) create mode 100644 tests/TestSuite_packet_capture.py diff --git a/tests/TestSuite_packet_capture.py b/tests/TestSuite_packet_capture.py new file mode 100644 index 0000000..638266e --- /dev/null +++ b/tests/TestSuite_packet_capture.py @@ -0,0 +1,892 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2018 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +DPDK Test suite. +Test support packet_capture features of dpdk-pdump tool +''' + +import os +import traceback + +import time +import re +import types +import random +from pprint import pformat + +from scapy.utils import rdpcap +from scapy.packet import NoPayload +from scapy.packet import Packet as scapyPacket +from scapy.fields import ConditionalField,Emph +from scapy.base_classes import SetGen + +from test_case import TestCase +from exception import VerifyFailure +from pmd_output import PmdOutput +from packet import Packet, sniff_packets, load_sniff_packets + +from settings import load_global_setting, DEBUG_SETTING + +if load_global_setting(DEBUG_SETTING) == "yes": + print_flag = True +else: + print_flag = False + +jSep = os.sep.join + +class parsePacket(object): + ''' + this class is used to parse pcap files' packets' layer content + ''' + def __init__(self, filename, skip_flag=False): + self.pcapFile = filename + self.packetLayers = dict() + self.skip = skip_flag + + def parse_packet_layer(self, pkt_object): + ''' + parse one packet every layers' fields and value + ''' + if pkt_object == None: + return + + self.packetLayers[pkt_object.name] = dict() + for curfield in pkt_object.fields_desc: + if isinstance(curfield, ConditionalField) and \ + not curfield._evalcond(pkt_object): + continue + field_value = pkt_object.getfieldval(curfield.name) + if isinstance(field_value, scapyPacket) or (curfield.islist and \ + curfield.holds_packets and type(field_value) is list): + continue + repr_value = curfield.i2repr(pkt_object, field_value) + if isinstance(repr_value, str): + repr_value = repr_value.replace(os.linesep, + os.linesep + " "*(len(curfield.name) +4)) + self.packetLayers[pkt_object.name][curfield.name] = repr_value + + if isinstance(pkt_object.payload, NoPayload): + return + else: + self.parse_packet_layer(pkt_object.payload) + + def get_valid_packet(self, pcap_pkts_origin, number): + cnt = 0 + for packet in pcap_pkts_origin: + self.parse_packet_layer(packet) + if self.skip: + flag = 'LLDP' not in self.packetLayers.keys() + else: + flag = True + if self.packetLayers["Ethernet"]['dst'] == 'ff:ff:ff:ff:ff:ff' and \ + flag: + if number == cnt: + break + cnt += 1 + self.packetLayers.clear() + + def parse_pcap(self, number=0): + ''' + parse one packet content + ''' + pcap_pkts = [] + try: + if os.path.exists(self.pcapFile) == False: + warning = "{0} is not exist !".format(self.pcapFile) + return warning + + pcap_pkts = rdpcap(self.pcapFile) + # parse packets' every layers and fields + if len(pcap_pkts) == 0: + warning = "{0} is empty".format(self.pcapFile) + return warning + elif number>= len(pcap_pkts): + warning = "{0} is missing No.{1} packet".format( + self.pcapFile, number) + return warning + + self.get_valid_packet(pcap_pkts, number) + + except Exception,e: + print (e) + finally: + pass + + return None + +class TestPacketCapture(TestCase): + @property + def driver(self): + return self.kdriver + + @property + def is_deubg(self): + return self._enable_debug + + def set_up_all(self): + ''' + Run at the start of each test suite. + ''' + self.ports = self.dut.get_ports() + self.verify(self.target == "x86_64-native-linuxapp-gcc", + "only support x86_64-native-linuxapp-gcc") + self.verify(len(self.ports) >= 2, "Insufficient ports for testing") + self.test_port0_id = 0 + self.test_port1_id = 1 + # compile dpdk app with SW CONFIG_RTE_LIBRTE_PMD_PCAP open + self.dut_skip_compile = self.dut.skip_setup + #------------------------------------------------------------------ + # used for save log + self.pdump_output = jSep(["/root", 'pdumpLog']) + if not self.is_existed(self.pdump_output): + cmd = "mkdir -p {0}".format(self.pdump_output) + self.dut.send_expect(cmd, "# ") + ##################################################################### + if not (self.dut_skip_compile and self.check_pcap_lib()): + self.pcap_SW = "CONFIG_RTE_LIBRTE_PMD_PCAP" + cmd = "sed -i -e 's/{0}=n$/{0}=y/' config/common_base".format( + self.pcap_SW) + self.dut.send_expect(cmd, "# ", 30) + self.dut.skip_setup = False + self.dut.build_install_dpdk(self.target) + ##################################################################### + self.session_ex = self.dut.new_session() + # secondary process (dpdk-pdump) + self.pdump_dir = self.dut.base_dir + os.sep + \ + "%s/build/app/pdump/" % self.target + cmd = "ls {0} -F | grep '*'".format(self.pdump_dir) + exe_files = self.dut.send_expect(cmd, "# ").splitlines() + if len(exe_files) == 1: + self.tool_name = exe_files[0][:-1] + else: + self.verify(False, "tool name exception !") + self.dut_dpdk_pdump_dir = self.dut.base_dir + os.sep + \ + "%s/app/%s" % (self.target, self.tool_name) + self.dpdk_pdump = self.dut_dpdk_pdump_dir + \ + " --file-prefix=test -- --pdump " + # every option string length should be less than 32 bytes +# self.dpdk_pdump = self.dut_dpdk_pdump_dir + " -- --pdump " + self.send_pcap = jSep([self.pdump_output, "scapy_%s_%s_%d.pcap"]) + self.rx_pcap = jSep([self.pdump_output, "pdump-rx.pcap"]) + self.tx_pcap = jSep([self.pdump_output, "pdump-tx.pcap"]) + self.rxtx_pcap = jSep([self.pdump_output, "pdump-rxtx.pcap"]) + self.rx_iface = None + self.tx_iface = None + self.rxtx_iface = None + self.rx_packet_pos = 0 + self.tx_packet_pos = 0 + self.dev_iface_flag = False + # primary process + self.pmdout = PmdOutput(self.dut) + + # False: reduce test items for regression testing, + # shut off base test environment checking + # True: make a full range testing + self.full_test = True + # get tcpdump options + self.check_tcpdump_options() + + def is_existed(self, path): + ''' check if file existed ''' + cmd = "ls {0}".format(path) + self.dut.send_expect(cmd, "# ") + cmd = "echo $?" + output = self.dut.send_expect(cmd, "# ") + ret = True if output == "0" else False + + return ret + + def check_tcpdump_options(self): + param = "" + direct_param = r"(\s+)\[ -(\w) in\|out\|inout \]" + tcpdump_help = self.dut.send_expect("tcpdump -h", "# ") + for line in tcpdump_help.split('\n'): + m = re.match(direct_param, line) + if m: + param = "-" + m.group(2) + " out" + self.tcpdump = "tcpdump -i {0} " + param + " -w {1} >/dev/null 2>&1 &" + + def check_pcap_lib(self): + pcap_lib_dir = os.sep.join([self.dut.base_dir, + self.target, + "lib/librte_pmd_pcap.a"]) + self.dut.send_expect("ll %s"%pcap_lib_dir, "# ") + if self.dut.send_expect("echo $?", "# ") == "0": + return True + else: + return False + + def get_packet_types(self): + ''' + ''' + packet_types = ["TCP", + "UDP", + "SCTP", + "TIMESYNC", + "ARP", + "LLDP", + "IP_RAW", + "IPv6_TCP", + "IPv6_UDP", + "IPv6_SCTP", + "VLAN_UDP"] + + if self.full_test: + test_packet_types = packet_types + else: + test_packet_types = ["IPv6_TCP"] + + return test_packet_types + + def generate_options(self, port_id, pci, intf, types): + port_types = ["port=%d,"%port_id, + "device_id=%s,"%pci] + dump_pcap_types = [["tx-dev={0},rx-dev={1},".format(self.tx_pcap, + self.rx_pcap), + {"rx": [self.rx_pcap, 1], + "tx": [self.tx_pcap, 1]}], + ["rx-dev={0},".format(self.rx_pcap), + {"rx": [self.rx_pcap, 1], + "tx": [None, 0]}], + ["tx-dev={0},".format(self.tx_pcap), + {"rx": [None, 0], + "tx": [self.tx_pcap, 1]}], + ] + dump_iface_types = [["tx-dev={0},rx-dev={1},".format(self.tx_iface, + self.rx_iface), + {"rx": [self.rx_pcap, 1], + "tx": [self.tx_pcap, 1]}], + ["rx-dev={0},".format(self.rx_iface), + {"rx": [self.rx_pcap, 1], + "tx": [None, 0]}], + ["tx-dev={0},".format(self.tx_iface), + {"rx": [None, 0], + "tx": [self.tx_pcap, 1]}] + ] + + queue_types = ["queue=*,", "queue=0,"] + # ring size + maxPower = 27 + minPower = 1 + ring_size_types = ["ring-size=%d,"%(2**minPower), + "ring-size=%d,"% (2**random.randint(minPower+1, + maxPower)), + "ring-size=%d,"%(2**maxPower)] + # mbuf size + max_mbuf_size = 50000 #59520 + min_mbuf_size = 252 + mbuf_size_types = ["mbuf-size=%d,"%min_mbuf_size, + "mbuf-size=%d,"%random.randint(min_mbuf_size+1, + max_mbuf_size), + "mbuf-size=%d,"%max_mbuf_size] + # total number mbuf + max_total_num_mbufs = 65535 + min_total_num_mbufs = 1025 + total_num_mbufs_types = [ + "total-num-mbufs=%d,"%min_total_num_mbufs, + "total-num-mbufs=%d,"%random.randint(min_total_num_mbufs+1, + max_total_num_mbufs), + "total-num-mbufs=%d,"%max_total_num_mbufs] + + if "port" in types: + port_num = len(port_types) + else: + port_num = 1 + + if "dev-pcap" in types: + dump_types = dump_pcap_types + elif "dev-iface" in types: + dump_types = dump_iface_types + else: + dump_types = dump_pcap_types[:1] + + if "queue" in types: + queue_num = len(queue_types) + else: + queue_num = 1 + + option_exds = [""] + if "ring_size" in types: + option_exds = ring_size_types[:] + + if "mbuf_size" in types: + option_exds = mbuf_size_types[:] + + if "total_num_mbufs" in types: + option_exds = total_num_mbufs_types[:] + + options = list() + for port in port_types[:port_num]: + for queue in queue_types[:queue_num]: + for dump in dump_types: + for option_exd in option_exds: + options.append([ + ((port + queue+ dump[0]) + option_exd)[:-1], + dump[1]]) + + return options + + def set_up(self): + ''' + Run before each test case. + ''' + self.exit_flag = False + + def compare_pkts(self, refPkt=None, targetPkt=None, pkt_type=None, + refPacketNo=0, targetPacketNo=0): + ''' + compare two pcap files' specified packet content + ''' + if self.is_deubg: + msgs = [ + " " + "*"*50, + " <%s> No.%d packet is the reference packet"%(refPkt, + refPacketNo), + " <%s> No.%d packet is the target packet"%(targetPkt, + targetPacketNo), + " " + "*"*50] + self.logger.info(os.linesep.join(msgs)) + warning = None + refObj = parsePacket(refPkt) + warning = refObj.parse_pcap(number=refPacketNo) + if warning: + return warning + # dpdk vlan doesn't add a `802.1Q` field in packet, remove this before + # comparison + # remove it for dpdk has realized it after 18.02 +# if pkt_type == 'VLAN_UDP' and '802.1Q' in refObj.packetLayers.keys(): +# refObj.packetLayers['Ethernet']['type'] = \ +# refObj.packetLayers['802.1Q']['type'] +# refObj.packetLayers.pop('802.1Q') + + targetObj = parsePacket(targetPkt) + warning = targetObj.parse_pcap(number=targetPacketNo) + if warning: + return warning + #------------------------------------------------------------------ + # remove some fields, which are filled by dpdk automatically + # if packet is filled with `Padding`, remove this + if "Padding" in targetObj.packetLayers.keys(): + targetObj.packetLayers.pop("Padding") + if len(refObj.packetLayers) != len(targetObj.packetLayers): + refObj_layer = pformat(refObj.packetLayers) + targetObj_layer = pformat(targetObj.packetLayers) + self.logger.info(os.linesep + "refObj: %s"%refObj_layer) + self.logger.info(os.linesep + "targetObj: %s"%targetObj_layer) + warning = "packet {0} layers are not as expected".format(targetPkt) + return warning + + for layer in refObj.packetLayers.keys(): + if layer not in targetObj.packetLayers.keys(): + warning = "{0} has no [{1}] layer".format(targetPkt, layer) + return warning + + if (pkt_type in ['TIMESYNC', 'VLAN_UDP']) and layer == 'Raw': + continue + + refLayerFields = refObj.packetLayers[layer] + targetLayerFields = targetObj.packetLayers[layer] + if len(refLayerFields) != len(targetLayerFields): + warning = "{0} [{1}] layer has no expected fields".format( + targetPkt, layer) + return warning + + for field in refLayerFields.keys(): + if field == 'src' or field == 'dst': + continue + if field not in targetLayerFields.keys(): + warning = ("{0} layer [{1}] " + "has no [{2}] field").format(targetPkt, + layer, field) + return warning + if refLayerFields[field] != targetLayerFields[field]: + warning = ("{0} [{1}] layer [{2}] " + "field has no expected value").format(targetPkt, + layer, + field) + return warning + + return warning + + def clear_ASLR(self): + cmd = "echo 0 > /proc/sys/kernel/randomize_va_space" + self.session_ex.send_expect(cmd, "# ", timeout=10) + time.sleep(2) + + def reset_ASLR(self): + cmd = "echo 2 > /proc/sys/kernel/randomize_va_space" + self.session_ex.send_expect(cmd, "# ", timeout=10) + time.sleep(4) + + def start_testpmd(self): + self.dut.send_expect("rm -fr {0}/*".format(self.pdump_output), + "# ", timeout=10) + offloadd = '0x1fbf' if self.driver == 'i40e' else '0x2203f' + param_opt = "--port-topology=chained --tx-offloads={0}".format(offloadd) + # boot up testpmd + self.pmdout.start_testpmd("Default", + param=param_opt, + ) + self.pmdout.execute_cmd("set fwd io") + self.pmdout.execute_cmd("start") + time.sleep(2) + + def stop_testpmd(self): + # quit testpmd + self.pmdout.execute_cmd("stop") + self.pmdout.quit() + time.sleep(2) + + def check_dut_file_exist(self, file_path): + self.session_ex.send_expect("ll %s"%file_path, "# ") + if self.session_ex.send_expect("echo $?", "# ") == "0": + return True + else: + return False + + def start_tcpdump_pdump_iface(self, option): + if option["rx"][0] != None and option["tx"][0] != None and \ + option["rx"][0] == option["tx"][0]: + if self.check_dut_file_exist(self.rxtx_pcap): + self.session_ex.send_expect("rm -f %s"%self.rxtx_pcap, "# ") + cmd = self.tcpdump.format(self.rxtx_iface, self.rxtx_pcap) + self.session_ex.send_expect(cmd, "# ") + else: + if option["rx"][0] != None: + if self.check_dut_file_exist(self.rx_pcap): + self.session_ex.send_expect("rm -f %s"%self.rx_pcap, "# ") + cmd = self.tcpdump.format(self.rx_iface, self.rx_pcap) + self.session_ex.send_expect(cmd, "# ") + + if option["tx"][0] != None: + if self.check_dut_file_exist(self.tx_pcap): + self.session_ex.send_expect("rm -f %s"%self.tx_pcap, "# ") + cmd = self.tcpdump.format(self.tx_iface, self.tx_pcap) + self.session_ex.send_expect(cmd, "# ") + time.sleep(4) + + def stop_tcpdump_pdump_iface(self): + self.session_ex.send_expect("killall tcpdump", "# ", 5) + time.sleep(2) + + def start_dpdk_pdump(self, option): + # boot up dpdk-pdump tool with packet_capture feature set + # delete last time dumped files + self.session_ex.send_expect("rm -fr {0}/*".format(self.pdump_output), + "# ") + self.session_ex.send_expect("cd %s"%self.dut.base_dir, "# ") + if self.is_deubg: # for debugging + curTime = time.localtime() + microTime = "%04d%02d%02d-%02d_%02d_%02d"%( curTime.tm_year, + curTime.tm_mon, + curTime.tm_mday, + curTime.tm_hour, + curTime.tm_min, + curTime.tm_sec) + if self.check_dut_file_exist("/root/pdump/") == False: + self.session_ex.send_expect("mkdir /root/pdump", "# ") + cmd = "echo %s "%self.dpdk_pdump + \ + " '%s' > /root/pdump/pdump_%s.log &"%(option[0], microTime) + self.session_ex.send_expect(cmd, "# ") + cmd = self.dpdk_pdump + \ + " '%s' >> /root/pdump/pdump_%s.log &"%(option[0], microTime) + else: + cmd = self.dpdk_pdump + " '%s' >/dev/null 2>&1 &"%(option[0]) + self.logger.info(cmd) + self.session_ex.send_expect(cmd, "# ", 15) + time.sleep(6) + + def check_pdump_ready(self, option): + rx_dump_pcap = option["rx"][0] + if rx_dump_pcap: + self.verify(self.check_dut_file_exist(rx_dump_pcap), + "{1} {0} is not ready".format(rx_dump_pcap, + self.tool_name)) + tx_dump_pcap = option["tx"][0] + if tx_dump_pcap: + self.verify(self.check_dut_file_exist(tx_dump_pcap), + "{1} {0} is not ready".format(tx_dump_pcap, + self.tool_name)) + + def stop_dpdk_pdump(self): + # quit dpdk-pdump + self.session_ex.send_expect("killall %s"%self.tool_name, "# ", 5) + time.sleep(3) + + def packet_capture_dump_packets(self, pkt_type, number, **kwargs): + if pkt_type == 'VLAN_UDP': + self.pmdout.execute_cmd("vlan set filter off 0") + self.pmdout.execute_cmd("vlan set filter off 1") + self.pmdout.execute_cmd("start") + # tester's port 0 and port 1 work under chained mode. + port_0 = self.ports[self.test_port0_id] + port_1 = self.ports[self.test_port1_id] + ################################################ + # check send tx packet by port 0 + # send packet to dut and compare dpdk-pdump dump pcap with + # scapy pcap file + intf = self.tester.get_interface(self.tester.get_local_port(port_1)) + + # prepare to catch replay packet in out port + recPaket = jSep(['/tmp', "sniff_%s.pcap" % intf]) + if os.path.exists(recPaket): + os.remove(recPaket) + inst = sniff_packets(intf, count=1, timeout=20) + pkt = Packet(pkt_type=pkt_type) + if pkt_type == 'VLAN_UDP': + pkt.config_layer('dot1q', {'vlan': 20}) + src_mac = self.tester.get_mac(self.tester.get_local_port(port_0)) + pkt.config_layer('ether', {'src': src_mac}) + # save send packet in a pcap file + refPaket = self.send_pcap % (pkt_type, "rx", number) + if os.path.exists(refPaket): + os.remove(refPaket) + pkt.pktgen.write_pcap(refPaket) + # send out test packet + tester_port = self.tester.get_local_port(port_0) + intf = self.tester.get_interface(tester_port) + pkt.send_pkt(tx_port=intf) + # load pcap file catched by out port + time.sleep(1) + load_sniff_packets(inst) + # compare pcap file received by out port with scapy reference + # packet pcap file + warning = self.compare_pkts(refPaket, recPaket, pkt_type) + msg = "tcpdump rx Receive Packet error: {0}".format(warning) + self.verify(warning == None, msg) + ################################################ + # check send tx packet by port 1 + # send packet to dut and compare dpdk-pdump dump pcap + # with scapy pcap file + intf = self.tester.get_interface(self.tester.get_local_port(port_0)) + # prepare to catch replay packet in out port + recPaket = jSep(['/tmp', "sniff_%s.pcap" % intf]) + if os.path.exists(recPaket): + os.remove(recPaket) + inst = sniff_packets(intf, count=1, timeout=20) + pkt = Packet(pkt_type=pkt_type) + if pkt_type == 'VLAN_UDP': + pkt.config_layer('dot1q', {'vlan': 20}) + src_mac = self.tester.get_mac(self.tester.get_local_port(port_1)) + pkt.config_layer('ether', {'src': src_mac}) + # save send packet in a pcap file + refPaket = self.send_pcap % (pkt_type, "tx", number) + if os.path.exists(refPaket): + os.remove(refPaket) + pkt.pktgen.write_pcap(refPaket) + # send out test packet + tester_port = self.tester.get_local_port(port_1) + intf = self.tester.get_interface(tester_port) + pkt.send_pkt(tx_port=intf) + # load pcap file catched by out port + time.sleep(1) + load_sniff_packets(inst) + # compare pcap file received by out port + # with scapy reference packet pcap file + warning = self.compare_pkts(refPaket, recPaket, pkt_type) + msg = "tcpdump tx Receive Packet error: {0}".format(warning) + self.verify(warning == None, msg) + + def packet_capture_check_pdump_pcaps(self, pkt_type, number, **kwargs): + ################################################ + rx_dump_pcap = kwargs["rx"][0] + if rx_dump_pcap: + self.verify(os.path.exists(rx_dump_pcap), + "{0} doesn't exist".format(rx_dump_pcap)) + # save send packet in a pcap file + refPaket = self.send_pcap % (pkt_type, "rx", number) + self.verify(os.path.exists(refPaket), + "{0} doesn't exist".format(refPaket)) + # compare pcap file dumped by dpdk-pdump + # with scapy reference packet pcap file + warning = self.compare_pkts(refPaket, rx_dump_pcap, pkt_type, + targetPacketNo=self.rx_packet_pos) + if kwargs["rx"][1] == 2: + self.rx_packet_pos += kwargs["rx"][1] + else: + self.rx_packet_pos += 1 + self.verify(warning == None, + "dpdk-pdump rx dump packet error: {0}".format(warning)) + msg = "pdump rx {0} packet content is correct".format(pkt_type) + self.logger.info(msg) + ################################################ + tx_dump_pcap = kwargs["tx"][0] + if tx_dump_pcap: + self.verify(os.path.exists(tx_dump_pcap), + "{0} doesn't exist".format(tx_dump_pcap)) + # set send packet + refPaket = self.send_pcap % (pkt_type, "tx", number) + self.verify(os.path.exists(refPaket), + "{0} doesn't exist".format(refPaket)) + # compare pcap file dumped by dpdk-pdump + # with scapy reference packet pcap file + if kwargs["tx"][1] == 2 and self.tx_packet_pos == 0: + self.tx_packet_pos = 1 + warning = self.compare_pkts(refPaket, tx_dump_pcap, pkt_type, + targetPacketNo=self.tx_packet_pos) + if kwargs["tx"][1] == 2: + self.tx_packet_pos += kwargs["tx"][1] + else: + self.tx_packet_pos += 1 + msg = "dpdk-pdump tx dump packet error: {0}".format(warning) + self.verify(warning == None, msg) + msg = "pdump tx {0} packet content is correct".format(pkt_type) + self.logger.info(msg) + + def packet_capture_test_packets(self, option): + self.clear_ASLR() + self.start_testpmd() + self.start_dpdk_pdump(option) + if self.dev_iface_flag == True: + self.start_tcpdump_pdump_iface(option[1]) + self.check_pdump_ready(option[1]) + number = 0 + for packet_type in self.get_packet_types(): + self.packet_capture_dump_packets(packet_type, number, **option[1]) + number += 1 + time.sleep(2) + if self.dev_iface_flag == True: + self.stop_tcpdump_pdump_iface() + if self.dut.get_ip_address() != self.tester.get_ip_address(): + # copy rx pdump data from dut + if os.path.exists(self.rx_pcap): + os.remove(self.rx_pcap) + self.dut.session.copy_file_from(self.rx_pcap, self.rx_pcap) + # copy tx pdump data from dut + if os.path.exists(self.tx_pcap): + os.remove(self.tx_pcap) + self.dut.session.copy_file_from(self.tx_pcap, self.tx_pcap) + self.stop_dpdk_pdump() + self.stop_testpmd() + + number = 0 + self.rx_packet_pos = 0 + self.tx_packet_pos = 0 + for packet_type in self.get_packet_types(): + self.packet_capture_check_pdump_pcaps(packet_type, number, + **option[1]) + number += 1 + time.sleep(2) + self.reset_ASLR() + + def packet_capture_test_options(self, pdump_options): + try: + for option in pdump_options: + self.packet_capture_test_packets(option) + + self.exit_flag = True + except Exception as e: + self.logger.error(traceback.format_exc()) + raise VerifyFailure(e) + finally: + pass + + def test_pdump_port(self): + ''' + test different port options:: + * port= + * device_id= + ''' + port_id = self.test_port0_id + port_name = self.dut.ports_info[port_id]['intf'] + port_pci = self.dut.ports_info[port_id]['pci'] + test_types = ["port"] + options = self.generate_options( port_id, port_pci, port_name, + test_types) + self.packet_capture_test_options(options) + + def test_pdump_dev_pcap(self): + ''' + test different dump options with pcap files as output:: + * tx-dev=/xxx/pdump-tx.pcap,rx-dev=/xxx/pdump-rx.pcap + * rx-dev=/xxx/pdump-rx.pcap + * tx-dev=/xxx/pdump-tx.pcap + ''' + port_id = self.test_port0_id + port_name = self.dut.ports_info[port_id]['intf'] + port_pci = self.dut.ports_info[port_id]['pci'] + test_types = ["dev-pcap"] + options = self.generate_options( port_id, port_pci, port_name, + test_types) + self.packet_capture_test_options(options) + + def get_dut_iface(self): + # only physical nic support PROMISC + cmd = "ip link show | grep PROMISC | awk {'print $2'}" + out = self.dut.send_expect(cmd, "# ") + pat = "(.*):" + ifaces = [intf for intf in re.findall(pat, out, re.M) if intf] + # get dut/tester ip to check if they are in a platform + tester_ip = self.tester.get_ip_address() + dut_ip = self.dut.get_ip_address() + for link_port in range(len(self.ports)): + # if they are in a platform, ignore interface used by tester + if tester_ip == dut_ip: + tester_port = self.tester.get_local_port(link_port) + intf = self.tester.get_interface(tester_port) + if intf in ifaces: + ifaces.remove(intf) + # ignore interface used by dut + intf = self.dut.ports_info[link_port]['intf'] + if intf in ifaces: + ifaces.remove(intf) + + # set ports up + tmp_ifaces = ifaces[:] + for iface in tmp_ifaces: + # ignore current interface used by system + cmd = "ifconfig %s | grep 'inet ' "%iface + if self.dut.send_expect(cmd, "# ") != "": + ifaces.remove(iface) + self.dut.send_expect("ifconfig {0} up".format(iface), "# ") + time.sleep(10) + # get ports on link status + tmp_ifaces = ifaces[:] + for iface in tmp_ifaces: + cmd = "ip link show {0} | grep LOWER_UP".format(iface) + self.dut.send_expect(cmd, "# ") + output = self.dut.send_expect("echo $?".format(iface), "# ").strip() + if output != '0': + ifaces.remove(iface) + + self.verify(len(ifaces) >= 2, "Insufficient ports for iface testing") + # set iface port for pdump tool output dump packets + self.rx_iface = ifaces[0] + self.tx_iface = ifaces[1] + self.rxtx_iface = ifaces[0] + + def test_pdump_dev_iface(self): + ''' + test different dump options with interfaces as output:: + * tx-dev=,rx-dev= + * rx-dev= + * tx-dev= + ''' + self.get_dut_iface() + port_id = self.test_port0_id + port_name = self.dut.ports_info[port_id]['intf'] + port_pci = self.dut.ports_info[port_id]['pci'] + test_types = ["dev-iface"] + self.dev_iface_flag = True + options = self.generate_options( port_id, port_pci, port_name, + test_types) + self.packet_capture_test_options(options) + + def test_pdump_queue(self): + ''' + test different queue options:: + * first queue: + queue=0 + * all: + queue=* + ''' + port_id = self.test_port0_id + port_name = self.dut.ports_info[port_id]['intf'] + port_pci = self.dut.ports_info[port_id]['pci'] + test_types = ["queue"] + options = self.generate_options( port_id, port_pci, port_name, + test_types) + self.packet_capture_test_options(options) + + def test_pdump_ring_size(self): + ''' + test ring size option, set value within 2^[1~27] + ''' + port_id = self.test_port0_id + port_name = self.dut.ports_info[port_id]['intf'] + port_pci = self.dut.ports_info[port_id]['pci'] + test_types = ["ring_size"] + options = self.generate_options( port_id, port_pci, port_name, + test_types) + self.packet_capture_test_options(options) + + def test_pdump_mbuf_size(self): + ''' + test mbuf size option, set value within [252~59000]. + min value is decided by single packet size, + max value is decided by test platform memery size. + ''' + port_id = self.test_port0_id + port_name = self.dut.ports_info[port_id]['intf'] + port_pci = self.dut.ports_info[port_id]['pci'] + test_types = ["mbuf_size"] + + options = self.generate_options( port_id, port_pci, port_name, + test_types) + self.packet_capture_test_options(options) + + def test_pdump_total_num_mbufs(self): + ''' + test total-num-mbufs option, set value within [1025~65535] + ''' + port_id = self.test_port0_id + port_name = self.dut.ports_info[port_id]['intf'] + port_pci = self.dut.ports_info[port_id]['pci'] + test_types = ["total_num_mbufs"] + options = self.generate_options( port_id, port_pci, port_name, + test_types) + self.packet_capture_test_options(options) + + def tear_down(self): + ''' + Run after each test case. + ''' + if self.exit_flag == False: + self.stop_dpdk_pdump() + self.tester.send_expect("killall testpmd", "# ") + self.tester.send_expect("killall tcpdump", "# ") + if self.dev_iface_flag: + self.stop_tcpdump_pdump_iface() + self.dev_iface_flag = False + + def tear_down_all(self): + ''' + Run after each test suite. + ''' + if self.session_ex: + self.reset_ASLR() + self.session_ex.close() + self.session_ex = None + # Restore the config file and recompile the package. + if not (self.dut_skip_compile and self.check_pcap_lib()): + ################################################################### + self.dut.send_expect( + ("sed -i -e 's/{0}=y$/{0}=n/' " + "config/common_base").format(self.pcap_SW), "# ", 120) + # temporary disable skip_setup + skip_setup = self.dut.skip_setup + self.dut.skip_setup = True + self.dut.build_install_dpdk(self.target) + self.dut.skip_setup = skip_setup + ################################################################### + self.dut.kill_all() + \ No newline at end of file -- 1.9.3