From patchwork Tue Sep 8 03:26:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xiao, QimaiX" X-Patchwork-Id: 76828 Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id BD2A7A04AA; Tue, 8 Sep 2020 05:51:34 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B01911C19B; Tue, 8 Sep 2020 05:51:34 +0200 (CEST) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id 9E54E1C19B for ; Tue, 8 Sep 2020 05:51:33 +0200 (CEST) IronPort-SDR: JJ9HVxxgiXkQ642SvDqTBBtJTa7DRcfkQUDTwjQSzegOLr7uxigRKrPGXLWJqPY0hGf5LPFPp8 X3U0xGMXrh/Q== X-IronPort-AV: E=McAfee;i="6000,8403,9737"; a="158088235" X-IronPort-AV: E=Sophos;i="5.76,404,1592895600"; d="scan'208";a="158088235" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Sep 2020 20:51:32 -0700 IronPort-SDR: vihbIlF2WkgbxkrM7QRsZBo8dmhR2h13zV75A9y/5Kw8S9qRHkSAl9WqQCFT5I+pKUzqCZ4htL o/Y57dLm2Mag== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,404,1592895600"; d="scan'208";a="407003005" Received: from unknown (HELO localhost.localdomain) ([10.240.183.52]) by fmsmga001.fm.intel.com with ESMTP; 07 Sep 2020 20:51:31 -0700 From: Xiao Qimai To: dts@dpdk.org Cc: Xiao Qimai Date: Tue, 8 Sep 2020 03:26:41 +0000 Message-Id: <20200908032645.11852-4-qimaix.xiao@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200908032645.11852-1-qimaix.xiao@intel.com> References: <20200908032645.11852-1-qimaix.xiao@intel.com> MIME-Version: 1.0 Subject: [dts] [PATCH V1 3/7]framework/packet: update packet module for saving sending packet time 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" Signed-off-by: Xiao Qimai --- framework/packet.py | 159 +++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 76 deletions(-) diff --git a/framework/packet.py b/framework/packet.py index 603840b4..6a306cba 100644 --- a/framework/packet.py +++ b/framework/packet.py @@ -34,35 +34,54 @@ Base on scapy(python program for packet manipulation) """ from socket import AF_INET6 +from importlib import import_module from scapy.all import * -from scapy.layers.sctp import SCTP, SCTPChunkData - # load extension layers exec_file = os.path.realpath(__file__) DTS_PATH = exec_file.replace('/framework/packet.py', '') # exec_file might be .pyc file, if so, remove 'c'. TMP_PATH = DTS_PATH[:-1] + '/output/tmp/pcap/' if exec_file.endswith('.pyc') else DTS_PATH + '/output/tmp/pcap/' - if not os.path.exists(TMP_PATH): os.system('mkdir -p %s' % TMP_PATH) + DEP_FOLDER = DTS_PATH + '/dep' sys.path.append(DEP_FOLDER) - -from vxlan import VXLAN -from nvgre import NVGRE, IPPROTO_NVGRE -from scapy.contrib.gtp import * -from lldp import LLDP, LLDPManagementAddress -from Dot1BR import Dot1BR -from nsh import NSH -from mpls import MPLS -from igmp import IGMP -from pfcp import PFCP +sys.path.append(DEP_FOLDER + '/scapy_modules') from utils import convert_ip2int from utils import convert_int2ip -# for saving command history -from utils import get_backtrace_object +scapy_modules_required = {'nvgre': ['NVGRE', 'IPPROTO_NVGRE'], + 'gtp': ['GTP_U_Header', 'GTP_PDUSession_ExtensionHeader'], + 'lldp': ['LLDP', 'LLDPManagementAddress'], 'Dot1BR': ['Dot1BR'], 'pfcp': ['PFCP'], + 'nsh': ['NSH'], 'igmp': ['IGMP'], 'mpls': ['MPLS'], 'sctp': ['SCTP', 'SCTPChunkData'], 'vxlan': ['VXLAN']} +local_modules = [m[:-3] for m in os.listdir(DEP_FOLDER + '/scapy_modules') if (m.endswith('.py') and not m.startswith('__'))] + +for m in scapy_modules_required: + if m in local_modules: + module = import_module(m) + for clazz in scapy_modules_required[m]: + locals().update({clazz: getattr(module, clazz)}) + else: + if m == 'sctp': + module = import_module(f'scapy.layers.{m}') + for clazz in scapy_modules_required[m]: + locals().update({clazz: getattr(module, clazz)}) + else: + module = import_module(f'scapy.contrib.{m}') + for clazz in scapy_modules_required[m]: + locals().update({clazz: getattr(module, clazz)}) + +def get_scapy_module_impcmd(): + cmd_li = list() + for m in scapy_modules_required: + if m in local_modules: + cmd_li.append(f'from {m} import {",".join(scapy_modules_required[m])}') + else: + cmd_li.append(f'from scapy.contirb.{m} import {",".join(scapy_modules_required[m])}') + return ';'.join(cmd_li) + +SCAPY_IMP_CMD = get_scapy_module_impcmd() # packet generator type should be configured later PACKETGEN = "scapy" @@ -139,7 +158,7 @@ class scapy(object): def __init__(self): self.pkt = None - self.pkts = [] + self.pkts = list() def append_pkts(self): self.pkts.append(self.pkt) @@ -329,7 +348,7 @@ class scapy(object): pkt_layer.vni = vni def nsh(self, pkt_layer, ver=0, oam=0, critical=0, reserved=0, len=0, mdtype=1, nextproto=3, - nsp=0x0, nsi=1, npc= 0x0, nsc= 0x0, spc= 0x0, ssc= 0x0): + nsp=0x0, nsi=1, npc=0x0, nsc=0x0, spc=0x0, ssc=0x0): pkt_layer.Ver = ver pkt_layer.OAM = oam pkt_layer.Critical = critical @@ -354,7 +373,6 @@ class scapy(object): class Packet(object): - """ Module for config/create packet Based on scapy module @@ -469,8 +487,7 @@ class Packet(object): layer_li = [re.sub('\(.*?\)', '', i) for i in scapy_str.split('/')] self.pkt_type = '_'.join(layer_li) self._load_pkt_layers() - pkt = eval(scapy_str) - self.pktgen.assign_pkt(pkt) + self.pktgen.assign_pkt(scapy_str) def append_pkt(self, args=None, **kwargs): """ @@ -641,67 +658,58 @@ class Packet(object): self.pktgen.pkts.append(i) return p - def _send_pkt(self, crb, tx_port='', count=1, send_bg=False, loop=0, inter=0, timeout=15): + def send_pkt_bg_with_pcapfile(self, crb, tx_port='', count=1, loop=0, inter=0): """ - + send packet background with a pcap file, got an advantage in sending a large number of packets :param crb: session or crb object :param tx_port: ether to send packet :param count: send times - :param send_bg: send packet background :param loop: send packet in a loop - :param inter: interval time - :return: None + :param inter: interval time per packet + :return: send session """ - # save pkts to local pcap file, then copy to remote tester tmp directory - - time_stamp = str(time.time()) - pcap_file = 'scapy_{}.pcap'.format(tx_port) + time_stamp - self.save_pcapfile(crb, pcap_file) - scapy_cmd = 'scapy_{}.cmd'.format(tx_port) + time_stamp - cmd_str = 'from scapy.all import *\np=rdpcap("%s")\nprint("packet ready for sending...")\nfor i in p:\n\tprint(i.command())\nsendp(p, iface="%s", count=%d, loop=%d, inter=%0.3f, verbose=False)' % ( - crb.tmp_file + pcap_file, tx_port, count, loop, inter) - # write send cmd file to local tmp directory then copy to remote tester tmp folder - with open(TMP_PATH + scapy_cmd, 'w') as f: - f.write(cmd_str) - crb.session.copy_file_to(TMP_PATH + scapy_cmd, crb.tmp_file) - - if send_bg: # if send_bg create a new session to execute send action - session_prefix = 'scapy_bg_session' - scapy_session = crb.create_session(session_prefix + time_stamp) - scapy_session.send_command('python3 %s' % crb.tmp_file + scapy_cmd) + if crb.name != 'tester': + raise Exception('crb should be tester') + wrpcap('_', self.pktgen.pkts) + file_path = '/tmp/%s.pcap' % tx_port + scapy_session_bg = crb.prepare_scapy_env() + scapy_session_bg.copy_file_to('_', file_path) + scapy_session_bg.send_expect('pkts = rdpcap("%s")' % file_path, '>>> ') + scapy_session_bg.send_command('sendp(pkts, iface="%s",count=%s,loop=%s,inter=%s)' % (tx_port, count, loop, inter)) + return scapy_session_bg + + def _recompose_pkts_str(self, pkts_str): + method_pattern = re.compile('<.+?>') + method_li = method_pattern.findall(pkts_str) + for i in method_li: + pkts_str = method_pattern.sub(i.strip('<>')+'()', pkts_str, count=1) + return pkts_str + + def send_pkt(self, crb, tx_port='', count=1, interval=0, timeout=120): + p_str = '[' + ','.join([p.command() if not isinstance(p, str) else p for p in self.pktgen.pkts]) + ']' + pkts_str = self._recompose_pkts_str(pkts_str=p_str) + cmd = 'sendp(' + pkts_str + f',iface="{tx_port}",count={count},inter={interval},verbose=False)' + if crb.name == 'tester': + crb.scapy_session.send_expect(cmd, '>>> ', timeout=timeout) + elif crb.name.startswith("tester_scapy"): + crb.send_expect(cmd, '>>> ', timeout=timeout) else: - crb.send_expect('python3 %s' % crb.tmp_file + scapy_cmd, '# ', timeout=timeout) - return crb.tmp_file + scapy_cmd - - def send_pkt(self, crb, tx_port='', count=1, interval=0, timeout=15): - self._send_pkt(crb, tx_port, count, inter=interval, timeout=timeout) - - def send_pkt_bg(self, crb, tx_port='', count=-1, loop=1, interval=0, timeout=3): - return self._send_pkt(crb, tx_port=tx_port, count=count, send_bg=True, loop=loop, inter=interval, - timeout=timeout) - - def stop_send_pkt_bg(self, crb, filenames): + raise Exception("crb should be tester\'s session and initialized") + + def send_pkt_bg(self, crb, tx_port='', count=-1, interval=0, loop=1): + if crb.name != 'tester': + raise Exception('crb should be tester') + scapy_session_bg = crb.prepare_scapy_env() + p_str = '[' + ','.join([p.command() if not isinstance(p, str) else p for p in self.pktgen.pkts]) + ']' + pkts_str = self._recompose_pkts_str(pkts_str=p_str) + cmd = 'sendp(' + pkts_str + f',iface="{tx_port}",count={count},inter={interval},loop={loop},verbose=False)' + scapy_session_bg.send_command(cmd) + return scapy_session_bg + + @staticmethod + def stop_send_pkt_bg(session): # stop sending action - pids = [] - if isinstance(filenames, list): - for file in filenames: - out = crb.send_expect('ps -ef |grep %s|grep -v grep' % file, expected='# ') - try: - pids.append(re.search('\d+', out).group()) - except AttributeError as e: - print((e, ' :%s not killed' % file)) - else: - out = crb.send_expect('ps -ef |grep %s|grep -v grep' % filenames, expected='# ') - try: - pids.append(re.search('\d+', out).group()) - except AttributeError as e: - print((e, ' :%s not killed' % filenames)) - pid = ' '.join(pids) - if pid: - crb.send_expect('kill -9 %s' % pid, expected='# ') - for i in crb.sessions: - if i.name.startswith('scapy_bg_session'): - crb.destroy_session(i) + session.send_expect('^C', '>>> ') def check_layer_config(self): """ @@ -835,7 +843,8 @@ class Packet(object): if 'inner' in layer: layer = layer[6:] - + if isinstance(self.pktgen.pkt, str): + raise Exception('string type packet not support config layer') pkt_layer = self.pktgen.pkt.getlayer(idx) layer_conf = getattr(self.pktgen, layer) setattr(self, 'configured_layer_%s' % layer, True) @@ -1081,10 +1090,8 @@ def strip_pktload(pkt=None, layer="L2", p_index=0): ############################################################################### ############################################################################### if __name__ == "__main__": - pkt = Packet('Ether(type=0x894f)/NSH(Len=0x6,NextProto=0x0,NSP=0x000002,NSI=0xff)') sendp(pkt, iface='lo') - pkt.config_layer('ipv4', {'dst': '192.168.8.8'}) pkt.append_pkt(pkt_type='IPv6_TCP', pkt_len=100) pkt.append_pkt(pkt_type='TCP', pkt_len=100) pkt.config_layer('tcp', config={'flags': 'A'})