From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 3162BA0613 for ; Tue, 30 Jul 2019 14:18:31 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 272D61C10D; Tue, 30 Jul 2019 14:18:31 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id C73561C10A for ; Tue, 30 Jul 2019 14:18:28 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 30 Jul 2019 05:18:27 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,326,1559545200"; d="scan'208";a="162561196" Received: from fmsmsx108.amr.corp.intel.com ([10.18.124.206]) by orsmga007.jf.intel.com with ESMTP; 30 Jul 2019 05:18:27 -0700 Received: from fmsmsx153.amr.corp.intel.com (10.18.125.6) by FMSMSX108.amr.corp.intel.com (10.18.124.206) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 30 Jul 2019 05:18:27 -0700 Received: from shsmsx102.ccr.corp.intel.com (10.239.4.154) by FMSMSX153.amr.corp.intel.com (10.18.125.6) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 30 Jul 2019 05:18:26 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.112]) by shsmsx102.ccr.corp.intel.com ([169.254.2.19]) with mapi id 14.03.0439.000; Tue, 30 Jul 2019 20:18:24 +0800 From: "Wang, Yinan" To: "Mo, YufengX" , "dts@dpdk.org" CC: "Mo, YufengX" Thread-Topic: [dts] [PATCH V4]tests/packet_capture: upload automation script Thread-Index: AQHVRpsSqXFcsXPG7UuRXwGSv7R4D6bjFIcQ Date: Tue, 30 Jul 2019 12:18:24 +0000 Message-ID: References: <1564466015-44060-1-git-send-email-yufengx.mo@intel.com> <1564466015-44060-2-git-send-email-yufengx.mo@intel.com> In-Reply-To: <1564466015-44060-2-git-send-email-yufengx.mo@intel.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiNzJkMzNjZTctM2JmOS00NTNlLTgwODUtMTFhZTA0Y2E1ZWM2IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoiU3RmWE9jemFaUFwvanhpbFNHWm80a3J1QjFCemhEUmtUYVU4M1pueFlFRzhlOGNGbHc4K1V4SnpIbHR1Zjd2R2IifQ== x-ctpclassification: CTP_NT dlp-product: dlpe-windows dlp-version: 11.0.600.7 dlp-reaction: no-action x-originating-ip: [10.239.127.40] Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dts] [PATCH V4]tests/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: , Errors-To: dts-bounces@dpdk.org Sender: "dts" Acked-by: Wang, Yinan > -----Original Message----- > From: dts [mailto:dts-bounces@dpdk.org] On Behalf Of yufengmx > Sent: 2019=1B$BG/=1B(B7=1B$B7n=1B(B30=1B$BF|=1B(B 13:54 > To: dts@dpdk.org > Cc: Mo, YufengX > Subject: [dts] [PATCH V4]tests/packet_capture: upload automation script >=20 >=20 > Packet capture framework feature support packet capturing on dpdk Etherne= t > devices. DPDK provides dpdk-pdump tool under app/pdump directory for pack= et > capturing on dpdk. >=20 > Signed-off-by: yufengmx > --- > tests/TestSuite_packet_capture.py | 869 > ++++++++++++++++++++++++++++++++++++++ > 1 file changed, 869 insertions(+) > create mode 100644 tests/TestSuite_packet_capture.py >=20 > diff --git a/tests/TestSuite_packet_capture.py > b/tests/TestSuite_packet_capture.py > new file mode 100644 > index 0000000..4bab902 > --- /dev/null > +++ b/tests/TestSuite_packet_capture.py > @@ -0,0 +1,869 @@ > +# BSD LICENSE > +# > +# Copyright(c) 2010-2019 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 dpdk pdump tool features > +''' > +import random > +import os > +import traceback > +import time > +import re > +import signal > +import subprocess > +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 > + > +from test_case import TestCase > +from exception import VerifyFailure > +from pmd_output import PmdOutput > +from packet import Packet > + > + > +# These source code copy from packet.py module before > +sniff_packets/load_sniff_packets # refactor. New refactor methods have > +much more longer time consumption than # old methods. > + > +# Saved back groud sniff process id > +SNIFF_PIDS =3D {} > + > + > +def sniff_packets(intf, count=3D0, timeout=3D5, pcap=3DNone): > + """ > + sniff all packets for certain port in certain seconds. > + """ > + param =3D "" > + direct_param =3D r"(\s+)\[ -(\w) in\|out\|inout \]" > + tcpdump_help =3D subprocess.check_output( > + "tcpdump -h; echo 0", stderr=3Dsubprocess.STDOUT, shell=3DTrue) > + for line in tcpdump_help.split('\n'): > + m =3D re.match(direct_param, line) > + if m: > + param =3D "-" + m.group(2) + " in" > + > + if len(param) =3D=3D 0: > + print "tcpdump not support direction choice!!!" > + > + sniff_cmd =3D 'tcpdump -i %(INTF)s %(IN_PARAM)s -w %(FILE)s' > + options =3D {'INTF': intf, 'COUNT': count, 'IN_PARAM': param, > + 'FILE': '/tmp/sniff_%s.pcap' % intf if not pcap else pcap= } > + if count: > + sniff_cmd +=3D ' -c %(COUNT)d' > + cmd =3D sniff_cmd % options > + else: > + cmd =3D sniff_cmd % options > + > + args =3D cmd.split() > + pipe =3D subprocess.Popen(args) > + index =3D str(time.time()) > + SNIFF_PIDS[index] =3D (pipe, intf, timeout) > + time.sleep(0.5) > + return index > + > + > +def load_sniff_packets(index=3D''): > + pkts =3D [] > + child_exit =3D False > + if index in SNIFF_PIDS.keys(): > + pipe, intf, timeout =3D SNIFF_PIDS[index] > + time_elapse =3D int(time.time() - float(index)) > + while time_elapse < timeout: > + if pipe.poll() is not None: > + child_exit =3D True > + break > + > + time.sleep(1) > + time_elapse +=3D 1 > + > + if not child_exit: > + pipe.send_signal(signal.SIGINT) > + pipe.wait() > + > + # wait pcap file ready > + time.sleep(1) > + try: > + cap_pkts =3D rdpcap("/tmp/sniff_%s.pcap" % intf) > + for pkt in cap_pkts: > + # packet gen should be scapy > + packet =3D Packet(tx_port=3Dintf) > + packet.pktgen.assign_pkt(pkt) > + pkts.append(packet) > + except Exception as e: > + pass > + > + return pkts > + > + > +class parsePacket(object): > + > + def __init__(self, filename, skip_flag=3DFalse): > + self.pcapFile =3D filename > + self.packetLayers =3D dict() > + self.skip =3D skip_flag > + > + def parse_packet_layer(self, pkt_object): > + if pkt_object is None: > + return > + self.packetLayers[pkt_object.name] =3D dict() > + for curfield in pkt_object.fields_desc: > + if isinstance(curfield, ConditionalField) and \ > + not curfield._evalcond(pkt_object): > + continue > + field_value =3D 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 =3D curfield.i2repr(pkt_object, field_value) > + if isinstance(repr_value, str): > + repr_value =3D repr_value.replace( > + os.linesep, os.linesep + " " * (len(curfield.name) += 4)) > + self.packetLayers[pkt_object.name][curfield.name] =3D repr_v= alue > + if not isinstance(pkt_object.payload, NoPayload): > + self.parse_packet_layer(pkt_object.payload) > + > + def get_valid_packet(self, pcap_pkts_origin, number): > + cnt =3D 0 > + for packet in pcap_pkts_origin: > + self.parse_packet_layer(packet) > + flag =3D 'LLDP' not in self.packetLayers.keys() \ > + if self.skip else \ > + True > + src_ether =3D self.packetLayers["Ethernet"]['src'] > + if src_ether =3D=3D '00:00:00:00:00:00' and flag: > + if number =3D=3D cnt: > + break > + cnt +=3D 1 > + self.packetLayers.clear() > + > + def parse_pcap(self, number=3D0): > + pcap_pkts =3D [] > + try: > + if not os.path.exists(self.pcapFile): > + warning =3D "{0} is not exist !".format(self.pcapFile) > + return warning > + pcap_pkts =3D rdpcap(self.pcapFile) > + if len(pcap_pkts) =3D=3D 0: > + warning =3D "{0} is empty".format(self.pcapFile) > + return warning > + elif number >=3D len(pcap_pkts): > + warning =3D "{0} is missing No.{1} packet".format( > + self.pcapFile, number) > + return warning > + self.get_valid_packet(pcap_pkts, number) > + except Exception, e: > + print (e) > + > + return None > + > + > +class TestPacketCapture(TestCase): > + > + def is_existed_on_dut(self, check_path): > + self.dut.alt_session.send_expect("ls %s" % check_path, "# ") > + cmd =3D "echo $?" > + output =3D self.dut.alt_session.send_expect(cmd, "# ") > + ret =3D True if output and output.strip() =3D=3D "0" else False > + return ret > + > + def get_dut_iface_with_kernel_driver(self): > + # only physical nic support PROMISC > + cmd =3D "ip link show | grep PROMISC | awk {'print $2'}" > + out =3D self.dut.alt_session.send_expect(cmd, "# ") > + pat =3D "(.*):" > + ifaces =3D [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 =3D self.tester.get_ip_address() > + dut_ip =3D self.dut.get_ip_address() > + for link_port in range(len(self.dut_ports)): > + # if they are in a platform, ignore interface used by tester > + if tester_ip =3D=3D dut_ip: > + tester_port =3D self.tester.get_local_port(link_port) > + intf =3D self.tester.get_interface(tester_port) > + if intf in ifaces: > + ifaces.remove(intf) > + # ignore interface used by dut > + intf =3D self.dut.ports_info[link_port]['intf'] > + if intf in ifaces: > + ifaces.remove(intf) > + > + # set ports up > + tmp_ifaces =3D ifaces[:] > + for iface in tmp_ifaces: > + # ignore current interface used by system > + cmd =3D "ifconfig %s | grep 'inet ' " % iface > + if self.dut.alt_session.send_expect(cmd, "# ") !=3D "": > + ifaces.remove(iface) > + self.dut.alt_session.send_expect( > + "ifconfig {0} up".format(iface), "# ") > + time.sleep(10) > + # get ports on link status > + tmp_ifaces =3D ifaces[:] > + for iface in tmp_ifaces: > + cmd =3D "ip link show {0} | grep LOWER_UP".format(iface) > + self.dut.alt_session.send_expect(cmd, "# ") > + output =3D self.dut.alt_session.send_expect( > + "echo $?".format(iface), "# ").strip() > + if output !=3D '0': > + ifaces.remove(iface) > + > + self.verify(len(ifaces) >=3D 2, "Insufficient ports for iface te= sting") > + # set iface port for pdump tool output dump packets > + self.rx_iface =3D ifaces[0] > + self.tx_iface =3D ifaces[1] > + self.rxtx_iface =3D ifaces[0] > + > + def verify_supported_nic(self): > + supported_drivers =3D ['i40e', 'ixgbe'] > + result =3D all([self.dut.ports_info[index]['port'].default_drive= r in > + supported_drivers > + for index in self.dut_ports]) > + msg =3D "current nic is not supported" > + self.verify(result, msg) > + > + def get_tcpdump_options(self): > + param =3D "" > + direct_param =3D r"(\s+)\[ -(\w) in\|out\|inout \]" > + tcpdump_help =3D self.dut.alt_session.send_expect("tcpdump -h", = "# ") > + for line in tcpdump_help.split('\n'): > + m =3D re.match(direct_param, line) > + if m: > + param =3D "-" + m.group(2) + " out" > + self.tcpdump =3D "tcpdump -i {0} " + param + " -w {1} >/dev/null= 2>&1 &" > + > + def check_pcap_lib(self): > + pcap_lib_dir =3D os.sep.join([self.dut.base_dir, > + self.target, > + "lib/librte_pmd_pcap.a"]) > + return self.is_existed_on_dut(pcap_lib_dir) > + > + def get_packet_types(self): > + packet_types =3D ["TCP", > + "UDP", > + "SCTP", > + "TIMESYNC", > + "ARP", > + "LLDP", > + "IP_RAW", > + "IPv6_TCP", > + "IPv6_UDP", > + "IPv6_SCTP", > + "VLAN_UDP"] > + if self.pkt_index is None: # only initialize once > + self.pkt_index =3D random.randint(0, len(packet_types) - 1) > + test_packet_types =3D packet_types if self.full_test else \ > + [packet_types[self.pkt_index]] > + return test_packet_types > + > + def generate_options(self, port_id, pci, intf, types): > + port_types =3D ["port=3D%d," % port_id, > + "device_id=3D%s," % pci] > + dump_pcap_types =3D [ > + ["tx-dev=3D{0},rx-dev=3D{1},".format(self.tx_pcap, self.rx_p= cap), > + {"rx": [self.rx_pcap, 1], > + "tx": [self.tx_pcap, 1]}], > + ["rx-dev=3D{0},".format(self.rx_pcap), > + {"rx": [self.rx_pcap, 1], > + "tx": [None, 0]}], > + ["tx-dev=3D{0},".format(self.tx_pcap), > + {"rx": [None, 0], > + "tx": [self.tx_pcap, 1]}], ] > + dump_iface_types =3D [ > + ["tx-dev=3D{0},rx-dev=3D{1},".format(self.tx_iface, self.rx_= iface), > + {"rx": [self.rx_pcap, 1], > + "tx": [self.tx_pcap, 1]}], > + ["rx-dev=3D{0},".format(self.rx_iface), > + {"rx": [self.rx_pcap, 1], > + "tx": [None, 0]}], > + ["tx-dev=3D{0},".format(self.tx_iface), > + {"rx": [None, 0], > + "tx": [self.tx_pcap, 1]}]] > + > + queue_types =3D ["queue=3D*,", "queue=3D0,"] > + # ring size > + maxPower =3D 27 > + minPower =3D 1 > + ring_size_types =3D [ > + "ring-size=3D%d," % (2 ** minPower), > + "ring-size=3D%d," % (2 ** random.randint(minPower + 1, > maxPower)), > + "ring-size=3D%d," % (2 ** maxPower)] > + # mbuf size > + max_mbuf_size =3D 50000 > + min_mbuf_size =3D 252 > + mbuf_size_types =3D [ > + "mbuf-size=3D%d," % min_mbuf_size, > + "mbuf-size=3D%d," % random.randint(min_mbuf_size + 1, > max_mbuf_size), > + "mbuf-size=3D%d," % max_mbuf_size] > + # total number mbuf > + max_total_num_mbufs =3D 65535 > + min_total_num_mbufs =3D 1025 > + total_num_mbufs_types =3D [ > + "total-num-mbufs=3D%d," % min_total_num_mbufs, > + "total-num-mbufs=3D%d," % > random.randint(min_total_num_mbufs + 1, > + > max_total_num_mbufs), > + "total-num-mbufs=3D%d," % max_total_num_mbufs] > + > + port_num =3D len(port_types) if "port" in types else 1 > + > + if "dev-pcap" in types: > + dump_types =3D dump_pcap_types > + elif "dev-iface" in types: > + dump_types =3D dump_iface_types > + else: > + dump_types =3D dump_pcap_types[:1] > + > + queue_num =3D len(queue_types) if "queue" in types else 1 > + > + option_exds =3D [""] > + if "ring_size" in types: > + option_exds =3D ring_size_types[:] > + > + if "mbuf_size" in types: > + option_exds =3D mbuf_size_types[:] > + > + if "total_num_mbufs" in types: > + option_exds =3D total_num_mbufs_types[:] > + > + options =3D 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: > + opt =3D ((port + queue + dump[0]) + option_exd)[= :-1] > + msg =3D 'command line option string should be <= =3D 256' > + self.verify(len(opt) <=3D 256, msg) > + options.append([opt, dump[1]]) > + > + return options > + > + def compare_pkts(self, refPkt=3DNone, targetPkt=3DNone, pkt_type=3DN= one, > + refPacketNo=3D0, targetPacketNo=3D0): > + ''' compare two pcap files packet content ''' > + warning =3D None > + refObj =3D parsePacket(refPkt) > + warning =3D refObj.parse_pcap(number=3DrefPacketNo) > + if warning: > + return warning > + targetObj =3D parsePacket(targetPkt) > + warning =3D targetObj.parse_pcap(number=3DtargetPacketNo) > + 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) !=3D len(targetObj.packetLayers): > + refObj_layer =3D pformat(refObj.packetLayers) > + targetObj_layer =3D pformat(targetObj.packetLayers) > + self.logger.info(os.linesep + "refObj: %s" % refObj_layer= ) > + self.logger.info(os.linesep + "targetObj: %s" % targetObj_la= yer) > + warning =3D "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 =3D "{0} has no [{1}] layer".format(targetPkt, l= ayer) > + return warning > + > + if layer =3D=3D 'Raw': > + continue > + > + refLayerFields =3D refObj.packetLayers[layer] > + targetLayerFields =3D targetObj.packetLayers[layer] > + if len(refLayerFields) !=3D len(targetLayerFields): > + warning =3D "{0} [{1}] layer has no expected fields".for= mat( > + targetPkt, layer) > + return warning > + > + for field in refLayerFields.keys(): > + if field =3D=3D 'src' or field =3D=3D 'dst': > + continue > + if field not in targetLayerFields.keys(): > + warning =3D ("{0} layer [{1}] " > + "has no [{2}] field").format( > + targetPkt, layer, field) > + return warning > + if refLayerFields[field] !=3D targetLayerFields[field]: > + warning =3D ("{0} [{1}] layer [{2}] " > + "field has no expected value").format( > + targetPkt, layer, field) > + return warning > + > + return warning > + > + def clear_ASLR(self): > + cmd =3D "echo 0 > /proc/sys/kernel/randomize_va_space" > + self.dut.alt_session.send_expect(cmd, "# ", timeout=3D10) > + time.sleep(2) > + > + def reset_ASLR(self): > + cmd =3D "echo 2 > /proc/sys/kernel/randomize_va_space" > + self.dut.alt_session.send_expect(cmd, "# ", timeout=3D10) > + time.sleep(4) > + > + def start_testpmd(self): > + self.dut.alt_session.send_expect( > + "rm -fr {0}/*".format(self.pdump_log), "# ", 10) > + param_opt =3D "--port-topology=3Dchained" > + eal_param =3D '--file-prefix=3Dtest' > + self.testpmd.start_testpmd("Default", param=3Dparam_opt, > + eal_param=3Deal_param) > + self.testpmd.execute_cmd("set fwd io") > + self.testpmd.execute_cmd("start") > + time.sleep(2) > + > + def stop_testpmd(self): > + self.testpmd.execute_cmd("stop") > + self.testpmd.quit() > + time.sleep(2) > + > + def start_tcpdump_iface(self, option): > + if option["rx"][0] is not None and option["tx"][0] is not None a= nd \ > + option["rx"][0] =3D=3D option["tx"][0]: > + if self.is_existed_on_dut(self.rxtx_pcap): > + self.dut.alt_session.send_expect( > + "rm -f %s" % self.rxtx_pcap, "# ") > + cmd =3D self.tcpdump.format(self.rxtx_iface, self.rxtx_pcap) > + self.session_ex.send_expect(cmd, "# ") > + else: > + if option["rx"][0] is not None: > + if self.is_existed_on_dut(self.rx_pcap): > + self.dut.alt_session.send_expect( > + "rm -f %s" % self.rx_pcap, "# ") > + cmd =3D self.tcpdump.format(self.rx_iface, self.rx_pcap) > + self.session_ex.send_expect(cmd, "# ") > + > + if option["tx"][0] is not None: > + if self.is_existed_on_dut(self.tx_pcap): > + self.dut.alt_session.send_expect( > + "rm -f %s" % self.tx_pcap, "# ") > + cmd =3D self.tcpdump.format(self.tx_iface, self.tx_pcap) > + self.session_ex.send_expect(cmd, "# ") > + time.sleep(4) > + > + def stop_tcpdump_iface(self): > + self.dut.alt_session.send_expect("killall tcpdump", "# ", 5) > + time.sleep(2) > + > + def start_dpdk_pdump(self, option): > + length_limit =3D 256 > + msg =3D ('pdump option string length should be less than {}' > + ).format(length_limit) > + self.verify(len(option) < length_limit, msg) > + self.dut.alt_session.send_expect( > + "rm -fr {0}/*".format(self.pdump_log), "# ", 20) > + cmd =3D ';'.join([ > + "cd %s" % self.dut.base_dir, > + self.dpdk_pdump + " '%s' >/dev/null 2>&1 &" % (option[0])]) > + self.session_ex.send_expect(cmd, "# ", 15) > + time.sleep(6) > + > + def check_pdump_ready(self, option): > + rx_dump_pcap =3D option["rx"][0] > + if rx_dump_pcap: > + self.verify(self.is_existed_on_dut(rx_dump_pcap), > + "{1} {0} is not ready".format(rx_dump_pcap, > + self.tool_name)) > + tx_dump_pcap =3D option["tx"][0] > + if tx_dump_pcap: > + self.verify(self.is_existed_on_dut(tx_dump_pcap), > + "{1} {0} is not ready".format(tx_dump_pcap, > + self.tool_name)) > + > + def stop_dpdk_pdump(self): > + self.dut.alt_session.send_expect( > + "killall %s" % self.tool_name, "# ", 5) > + time.sleep(2) > + > + def packet_capture_dump_packets(self, pkt_type, number, **kwargs): > + self.logger.info('send <{}> packet'.format(pkt_type)) > + if pkt_type =3D=3D 'VLAN_UDP': > + self.testpmd.execute_cmd("vlan set filter off 0") > + self.testpmd.execute_cmd("vlan set filter off 1") > + self.testpmd.execute_cmd("start") > + # tester's port 0 and port 1 work under chained mode. > + port_0 =3D self.dut_ports[self.test_port0_id] > + port_1 =3D self.dut_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 =3D self.tester.get_interface(self.tester.get_local_port(po= rt_1)) > + # prepare to catch replay packet in out port > + recPkt =3D os.path.join('/tmp', "sniff_%s.pcap" % intf) > + if os.path.exists(recPkt): > + os.remove(recPkt) > + index =3D sniff_packets(intf, count=3D1, timeout=3D20, pcap=3Dre= cPkt) > + pkt =3D Packet(pkt_type=3Dpkt_type) > + if pkt_type =3D=3D 'VLAN_UDP': > + pkt.config_layer('dot1q', {'vlan': 20}) > + src_mac =3D 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 > + refPkt =3D self.send_pcap % (pkt_type, "rx", number) > + if os.path.exists(refPkt): > + os.remove(refPkt) > + pkt.pktgen.write_pcap(refPkt) > + # send out test packet > + tester_port =3D self.tester.get_local_port(port_0) > + intf =3D self.tester.get_interface(tester_port) > + pkt.send_pkt(tx_port=3Dintf) > + # load pcap file caught by out port > + time.sleep(1) > + load_sniff_packets(index) > + # compare pcap file received by out port with scapy reference > + # packet pcap file > + warning =3D self.compare_pkts(refPkt, recPkt, pkt_type) > + msg =3D "tcpdump rx Receive Packet error: {0}".format(warning) > + self.verify(not warning, msg) > + # check send tx packet by port 1 > + # send packet to dut and compare dpdk-pdump dump pcap > + # with scapy pcap file > + intf =3D self.tester.get_interface(self.tester.get_local_port(po= rt_0)) > + # prepare to catch replay packet in out port > + recPkt =3D os.path.join('/tmp', "sniff_%s.pcap" % intf) > + if os.path.exists(recPkt): > + os.remove(recPkt) > + index =3D sniff_packets(intf, count=3D1, timeout=3D20, pcap=3Dre= cPkt) > + pkt =3D Packet(pkt_type=3Dpkt_type) > + if pkt_type =3D=3D 'VLAN_UDP': > + pkt.config_layer('dot1q', {'vlan': 20}) > + src_mac =3D 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 > + refPkt =3D self.send_pcap % (pkt_type, "tx", number) > + if os.path.exists(refPkt): > + os.remove(refPkt) > + pkt.pktgen.write_pcap(refPkt) > + # send out test packet > + tester_port =3D self.tester.get_local_port(port_1) > + intf =3D self.tester.get_interface(tester_port) > + pkt.send_pkt(tx_port=3Dintf) > + # load pcap file caught by out port > + time.sleep(1) > + load_sniff_packets(index) > + # compare pcap file received by out port > + # with scapy reference packet pcap file > + warning =3D self.compare_pkts(refPkt, recPkt, pkt_type) > + msg =3D "tcpdump tx Receive Packet error: {0}".format(warning) > + self.verify(not warning, msg) > + > + def check_pdump_pcaps(self, pkt_type, number, **kwargs): > + rx_dump_pcap =3D 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 > + refPkt =3D self.send_pcap % (pkt_type, "rx", number) > + self.verify(os.path.exists(refPkt), > + "{0} doesn't exist".format(refPkt)) > + # compare pcap file dumped by dpdk-pdump > + # with scapy reference packet pcap file > + warning =3D self.compare_pkts(refPkt, rx_dump_pcap, pkt_type= , > + > targetPacketNo=3Dself.rx_packet_pos) > + if kwargs["rx"][1] =3D=3D 2: > + self.rx_packet_pos +=3D kwargs["rx"][1] > + else: > + self.rx_packet_pos +=3D 1 > + self.verify(warning is None, > + "dpdk-pdump rx dump packet error: > {0}".format(warning)) > + msg =3D "pdump rx {0} packet content is correct".format(pkt_= type) > + self.logger.info(msg) > + tx_dump_pcap =3D 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 > + refPkt =3D self.send_pcap % (pkt_type, "tx", number) > + self.verify(os.path.exists(refPkt), > + "{0} doesn't exist".format(refPkt)) > + # compare pcap file dumped by dpdk-pdump > + # with scapy reference packet pcap file > + if kwargs["tx"][1] =3D=3D 2 and self.tx_packet_pos =3D=3D 0: > + self.tx_packet_pos =3D 1 > + warning =3D self.compare_pkts(refPkt, tx_dump_pcap, pkt_type= , > + > targetPacketNo=3Dself.tx_packet_pos) > + if kwargs["tx"][1] =3D=3D 2: > + self.tx_packet_pos +=3D kwargs["tx"][1] > + else: > + self.tx_packet_pos +=3D 1 > + msg =3D "dpdk-pdump tx dump packet error: {0}".format(warnin= g) > + self.verify(warning is None, msg) > + msg =3D "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: > + self.start_tcpdump_iface(option[1]) > + self.check_pdump_ready(option[1]) > + for number, packet_type in enumerate(self.get_packet_types()): > + self.packet_capture_dump_packets(packet_type, number, > **option[1]) > + time.sleep(2) > + if self.dev_iface_flag: > + self.stop_tcpdump_iface() > + if self.dut.get_ip_address() !=3D self.tester.get_ip_address(): > + # copy rx pdump data from dut > + if self.is_existed_on_dut(self.rx_pcap): > + if os.path.exists(self.rx_pcap): > + os.remove(self.rx_pcap) > + self.dut.session.copy_file_from(self.rx_pcap, self.rx_pc= ap) > + # copy tx pdump data from dut > + if self.is_existed_on_dut(self.tx_pcap): > + if os.path.exists(self.tx_pcap): > + os.remove(self.tx_pcap) > + self.dut.session.copy_file_from(self.tx_pcap, self.tx_pc= ap) > + self.stop_dpdk_pdump() > + self.stop_testpmd() > + self.reset_ASLR() > + > + self.rx_packet_pos =3D 0 > + self.tx_packet_pos =3D 0 > + for number, packet_type in enumerate(self.get_packet_types()): > + self.check_pdump_pcaps(packet_type, number, **option[1]) > + time.sleep(2) > + > + def packet_capture_test_options(self, pdump_options): > + try: > + for option in pdump_options: > + self.packet_capture_test_packets(option) > + self.exit_flag =3D True > + except Exception as e: > + self.logger.error(traceback.format_exc()) > + raise VerifyFailure(e) > + > + def test_pdump_port(self): > + ''' > + test different port options:: > + *. port=3D > + *. device_id=3D > + ''' > + port_id =3D self.test_port0_id > + port_name =3D self.dut.ports_info[port_id]['intf'] > + port_pci =3D self.dut.ports_info[port_id]['pci'] > + test_types =3D ["port"] > + options =3D 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=3D/xxx/pdump-tx.pcap,rx-dev=3D/xxx/pdump-rx.pcap > + *. rx-dev=3D/xxx/pdump-rx.pcap > + *. tx-dev=3D/xxx/pdump-tx.pcap > + ''' > + port_id =3D self.test_port0_id > + port_name =3D self.dut.ports_info[port_id]['intf'] > + port_pci =3D self.dut.ports_info[port_id]['pci'] > + test_types =3D ["dev-pcap"] > + options =3D self.generate_options( > + port_id, port_pci, port_name, test_types) > + self.packet_capture_test_options(options) > + > + def test_pdump_dev_iface(self): > + ''' > + test different dump options with interfaces as output:: > + *. tx-dev=3D,rx-dev=3D > + *. rx-dev=3D > + *. tx-dev=3D > + ''' > + self.get_dut_iface_with_kernel_driver() > + port_id =3D self.test_port0_id > + port_name =3D self.dut.ports_info[port_id]['intf'] > + port_pci =3D self.dut.ports_info[port_id]['pci'] > + test_types =3D ["dev-iface"] > + self.dev_iface_flag =3D True > + options =3D 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=3D0 > + *. all: > + queue=3D* > + ''' > + port_id =3D self.test_port0_id > + port_name =3D self.dut.ports_info[port_id]['intf'] > + port_pci =3D self.dut.ports_info[port_id]['pci'] > + test_types =3D ["queue"] > + options =3D 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 =3D self.test_port0_id > + port_name =3D self.dut.ports_info[port_id]['intf'] > + port_pci =3D self.dut.ports_info[port_id]['pci'] > + test_types =3D ["ring_size"] > + options =3D 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~50000]. > + min value is decided by single packet size, > + max value is decided by test platform memory size. > + ''' > + port_id =3D self.test_port0_id > + port_name =3D self.dut.ports_info[port_id]['intf'] > + port_pci =3D self.dut.ports_info[port_id]['pci'] > + test_types =3D ["mbuf_size"] > + > + options =3D 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 =3D self.test_port0_id > + port_name =3D self.dut.ports_info[port_id]['intf'] > + port_pci =3D self.dut.ports_info[port_id]['pci'] > + test_types =3D ["total_num_mbufs"] > + options =3D self.generate_options( > + port_id, port_pci, port_name, test_types) > + self.packet_capture_test_options(options) > + > + def set_up_all(self): > + ''' > + Run at the start of each test suite. > + ''' > + self.verify(self.target =3D=3D "x86_64-native-linuxapp-gcc", > + "only support x86_64-native-linuxapp-gcc") > + self.dut_ports =3D self.dut.get_ports() > + self.verify(len(self.dut_ports) =3D=3D 2, "Insufficient ports fo= r testing") > + self.verify_supported_nic() > + self.test_port0_id =3D 0 > + self.test_port1_id =3D 1 > + # compile dpdk app with SW CONFIG_RTE_LIBRTE_PMD_PCAP open > + self.dut_skip_compile =3D self.dut.skip_setup > + # used for save log > + self.pdump_log =3D os.sep.join(["/root", 'pdumpLog']) > + if not self.is_existed_on_dut(self.pdump_log): > + cmd =3D "mkdir -p {0}".format(self.pdump_log) > + self.dut.alt_session.send_expect(cmd, "# ") > + if not (self.dut_skip_compile and self.check_pcap_lib()): > + self.pcap_SW =3D "CONFIG_RTE_LIBRTE_PMD_PCAP" > + cmd =3D "sed -i -e 's/{0}=3Dn$/{0}=3Dy/' config/common_base"= .format( > + self.pcap_SW) > + self.dut.alt_session.send_expect(cmd, "# ", 30) > + self.dut.skip_setup =3D False > + self.dut.build_install_dpdk(self.target) > + self.session_ex =3D self.dut.new_session() > + # secondary process (dpdk-pdump) > + self.pdump_dir =3D self.dut.base_dir + os.sep + \ > + "%s/build/app/pdump/" % self.target > + cmd =3D "ls {0} -F | grep '*'".format(self.pdump_dir) > + exe_files =3D self.dut.alt_session.send_expect(cmd, "# ").splitl= ines() > + if len(exe_files) =3D=3D 1: > + self.tool_name =3D exe_files[0][:-1] > + else: > + self.verify(False, "tool name exception !") > + self.dut_dpdk_pdump_dir =3D self.dut.base_dir + os.sep + \ > + "%s/app/%s" % (self.target, self.tool_name) > + self.dpdk_pdump =3D self.dut_dpdk_pdump_dir + \ > + " -v --file-prefix=3Dtest -- --pdump " > + self.send_pcap =3D os.sep.join([self.pdump_log, > "scapy_%s_%s_%d.pcap"]) > + self.rx_pcap =3D os.sep.join([self.pdump_log, "pdump-rx.pcap"]) > + self.tx_pcap =3D os.sep.join([self.pdump_log, "pdump-tx.pcap"]) > + self.rxtx_pcap =3D os.sep.join([self.pdump_log, "pdump-rxtx.pcap= "]) > + self.rx_iface =3D None > + self.tx_iface =3D None > + self.rxtx_iface =3D None > + self.rx_packet_pos =3D 0 > + self.tx_packet_pos =3D 0 > + self.dev_iface_flag =3D False > + # primary process > + self.testpmd =3D 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 =3D True > + # used on daily testing to avoid long time running > + self.pkt_index =3D None > + # get tcpdump options > + self.get_tcpdump_options() > + > + def set_up(self): > + ''' > + Run before each test case. > + ''' > + self.exit_flag =3D False > + > + def tear_down(self): > + ''' > + Run after each test case. > + ''' > + if not self.exit_flag: > + self.stop_dpdk_pdump() > + self.dut.alt_session.send_expect("killall testpmd", "# ") > + self.dut.alt_session.send_expect("killall tcpdump", "# ") > + self.reset_ASLR() > + if self.dev_iface_flag: > + self.stop_tcpdump_iface() > + self.dev_iface_flag =3D 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 =3D None > + # Restore the config file and recompile the package. > + if not (self.dut_skip_compile and self.check_pcap_lib()): > + > ############################################################# > ###### > + self.dut.alt_session.send_expect( > + ("sed -i -e 's/{0}=3Dy$/{0}=3Dn/' " > + "config/common_base").format(self.pcap_SW), "# ", 120) > + # temporary disable skip_setup > + skip_setup =3D self.dut.skip_setup > + self.dut.skip_setup =3D True > + self.dut.build_install_dpdk(self.target) > + self.dut.skip_setup =3D skip_setup > + > ############################################################# > ###### > + self.dut.kill_all() > -- > 1.9.3