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 E7472A2F6B for ; Tue, 8 Oct 2019 04:22:12 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D0E5D1BFEE; Tue, 8 Oct 2019 04:22:12 +0200 (CEST) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id E89261BF8C for ; Tue, 8 Oct 2019 04:22:10 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Oct 2019 19:22:09 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.67,269,1566889200"; d="scan'208";a="218146694" Received: from fmsmsx105.amr.corp.intel.com ([10.18.124.203]) by fmsmga004.fm.intel.com with ESMTP; 07 Oct 2019 19:22:09 -0700 Received: from fmsmsx119.amr.corp.intel.com (10.18.124.207) by FMSMSX105.amr.corp.intel.com (10.18.124.203) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 7 Oct 2019 19:22:09 -0700 Received: from shsmsx101.ccr.corp.intel.com (10.239.4.153) by FMSMSX119.amr.corp.intel.com (10.18.124.207) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 7 Oct 2019 19:22:08 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.166]) by SHSMSX101.ccr.corp.intel.com ([169.254.1.96]) with mapi id 14.03.0439.000; Tue, 8 Oct 2019 10:22:06 +0800 From: "Chen, Zhaoyan" To: "Xiao, QimaiX" , "dts@dpdk.org" CC: "Xiao, QimaiX" , "Chen, Zhaoyan" Thread-Topic: [dts] [PATCH V1] framework/packet: update packet module of dts Thread-Index: AQHVdRtoMSZFStjYNEOY77WhcHx2p6dQFB5g Date: Tue, 8 Oct 2019 02:22:06 +0000 Message-ID: <9DEEADBC57E43F4DA73B571777FECECA41DD7342@SHSMSX104.ccr.corp.intel.com> References: <20190927180539.2344-1-qimaix.xiao@intel.com> <20190927180539.2344-2-qimaix.xiao@intel.com> In-Reply-To: <20190927180539.2344-2-qimaix.xiao@intel.com> Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-product: dlpe-windows dlp-version: 11.2.0.6 dlp-reaction: no-action x-originating-ip: [10.239.127.40] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dts] [PATCH V1] framework/packet: update packet module of dts 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: Chen, Zhaoyan Regards, Zhaoyan Chen > -----Original Message----- > From: dts [mailto:dts-bounces@dpdk.org] On Behalf Of Qimai Xiao > Sent: Saturday, September 28, 2019 2:06 AM > To: dts@dpdk.org > Cc: Xiao, QimaiX > Subject: [dts] [PATCH V1] framework/packet: update packet module of dts >=20 > update API of packet and some other optimization >=20 > Signed-off-by: Qimai Xiao > --- > framework/packet.py | 665 +++++++++++++++++++++++--------------------- > 1 file changed, 354 insertions(+), 311 deletions(-) >=20 > diff --git a/framework/packet.py b/framework/packet.py index 502d85c..05b= 2367 > 100755 > --- a/framework/packet.py > +++ b/framework/packet.py > @@ -33,35 +33,19 @@ > Generic packet create, transmit and analyze module Base on scapy(python= program > for packet manipulation) """ > -import os > -import time > -import sys > -import re > -import signal > -import random > -import subprocess > -import shlex # separate command line for pipe > -from uuid import uuid4 > -from settings import FOLDERS > - > -import struct > + > from socket import AF_INET6 > -from scapy.all import conf > -from scapy.utils import wrpcap, rdpcap, hexstr -from scapy.layers.inet i= mport Ether, > IP, TCP, UDP, ICMP -from scapy.layers.inet6 import IPv6, IPv6ExtHdrRoutin= g, > IPv6ExtHdrFragment -from scapy.layers.l2 import Dot1Q, ARP, GRE > +from scapy.all import * > from scapy.layers.sctp import SCTP, SCTPChunkData -from scapy.sendrecv i= mport > sniff -from scapy.route import * -from scapy.packet import bind_layers, R= aw -from > scapy.sendrecv import sendp -from scapy.arch import get_if_hwaddr -from p= expect > import pxssh >=20 > # load extension layers > exec_file =3D os.path.realpath(__file__) > DTS_PATH =3D exec_file.replace('/framework/packet.py', '') > +# exec_file might be .pyc file, if so, remove 'c'. > +TMP_PATH =3D 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 =3D DTS_PATH + '/dep' > sys.path.append(DEP_FOLDER) >=20 > @@ -70,9 +54,8 @@ from nvgre import NVGRE, IPPROTO_NVGRE from lldp impor= t > LLDP, LLDPManagementAddress from Dot1BR import Dot1BR >=20 > -# get tester logger > -from logger import getLogger > -logger =3D getLogger('tester') > +from utils import convert_ip2int > +from utils import convert_int2ip >=20 > # for saving command history > from utils import get_backtrace_object > @@ -150,7 +133,16 @@ class scapy(object): >=20 > def __init__(self): > self.pkt =3D None > - pass > + self.pkts =3D [] > + > + def append_pkts(self): > + self.pkts.append(self.pkt) > + > + def update_pkts(self): > + if not self.pkts: # update pkt to a null pkt list. > + self.pkts.append(self.pkt) > + else: > + self.pkts[-1] =3D self.pkt >=20 > def assign_pkt(self, pkt): > self.pkt =3D pkt > @@ -179,14 +171,14 @@ class scapy(object): > if type is not None: > pkt_layer.type =3D type >=20 > - def strip_vlan(self, element): > + def strip_vlan(self, element, p_index=3D0): > value =3D None >=20 > - if self.pkt.haslayer('Dot1Q') is 0: > + if self.pkts[p_index].haslayer('Dot1Q') is 0: > return None >=20 > if element =3D=3D 'vlan': > - value =3D int(str(self.pkt[Dot1Q].vlan)) > + value =3D int(str(self.pkts[p_index][Dot1Q].vlan)) > return value >=20 > def etag(self, pkt_layer, ECIDbase=3D0, prio=3D0, type=3DNone): > @@ -197,19 +189,19 @@ class scapy(object): > if type is not None: > pkt_layer.type =3D type >=20 > - def strip_etag(self, element): > + def strip_etag(self, element, p_index=3D0): > value =3D None >=20 > - if self.pkt.haslayer('Dot1BR') is 0: > + if self.pkts[p_index].haslayer('Dot1BR') is 0: > return None >=20 > if element =3D=3D 'ECIDbase': > - value =3D int(str(self.pkt[Dot1BR].ECIDbase)) > + value =3D int(str(self.pkts[p_index][Dot1BR].ECIDbase)) > return value >=20 > - def strip_layer2(self, element): > + def strip_layer2(self, element, p_index=3D0): > value =3D None > - layer =3D self.pkt.getlayer(0) > + layer =3D self.pkts[p_index].getlayer(0) > if layer is None: > return None >=20 > @@ -222,9 +214,9 @@ class scapy(object): >=20 > return value >=20 > - def strip_layer3(self, element): > + def strip_layer3(self, element, p_index=3D0): > value =3D None > - layer =3D self.pkt.getlayer(1) > + layer =3D self.pkts[p_index].getlayer(1) > if layer is None: > return None >=20 > @@ -237,9 +229,9 @@ class scapy(object): >=20 > return value >=20 > - def strip_layer4(self, element): > + def strip_layer4(self, element, p_index=3D0): > value =3D None > - layer =3D self.pkt.getlayer(2) > + layer =3D self.pkts[p_index].getlayer(2) > if layer is None: > return None >=20 > @@ -252,7 +244,8 @@ class scapy(object): >=20 > return value >=20 > - def ipv4(self, pkt_layer, frag=3D0, src=3D"127.0.0.1", proto=3DNone,= tos=3D0, > dst=3D"127.0.0.1", chksum=3DNone, len=3DNone, version=3D4, flags=3DNone, = ihl=3DNone, ttl=3D64, > id=3D1, options=3DNone): > + def ipv4(self, pkt_layer, frag=3D0, src=3D"127.0.0.1", proto=3DNone,= tos=3D0, > dst=3D"127.0.0.1", chksum=3DNone, len=3DNone, > + version=3D4, flags=3DNone, ihl=3DNone, ttl=3D64, id=3D1, op= tions=3DNone): > pkt_layer.frag =3D frag > pkt_layer.src =3D src > if proto is not None: > @@ -287,7 +280,7 @@ class scapy(object): > pkt_layer.src =3D src > pkt_layer.dst =3D dst >=20 > - def tcp(self, pkt_layer, src=3D53, dst=3D53, flags=3DNone, len=3DNon= e, chksum=3DNone): > + def tcp(self, pkt_layer, src=3D53, dst=3D53, flags=3D0, len=3DNone, = chksum=3DNone): > pkt_layer.sport =3D src > pkt_layer.dport =3D dst > if flags is not None: > @@ -328,66 +321,6 @@ class scapy(object): > def vxlan(self, pkt_layer, vni=3D0): > pkt_layer.vni =3D vni >=20 > - def read_pcap(self, file): > - pcap_pkts =3D [] > - try: > - pcap_pkts =3D rdpcap(file) > - except: > - pass > - > - return pcap_pkts > - > - def write_pcap(self, file): > - try: > - wrpcap(file, self.pkt) > - except: > - pass > - > - def send_pcap_pkt(self, crb=3DNone, file=3D'', intf=3D'', count=3D1)= : > - if intf =3D=3D '' or file =3D=3D '' or crb is None: > - print "Invalid option for send packet by scapy" > - return > - > - content =3D 'pkts=3Drdpcap(\"%s\");sendp(pkts, iface=3D\"%s\", > count=3D\"%s\" );exit()' % (file, intf, count) > - cmd_file =3D '/tmp/scapy_%s.cmd' % intf > - > - crb.create_file(content, cmd_file) > - crb.send_expect("scapy -c scapy_%s.cmd &" % intf, "# ") > - > - def print_summary(self): > - # save command into test case history > - history_list =3D get_backtrace_object('test_case.py', 'test_hist= ory') > - if type(history_list) is list: > - history_list.append({"command": "p=3D%s" % self.pkt.command(= ), "name": > "Scapy", "output": ""}) > - > - logger.info("%s" % self.pkt.command()) > - > - def send_pkt(self, intf=3D'', count=3D1): > - self.print_summary() > - > - if intf !=3D '': > - # wait few seconds for link ready > - countdown =3D 600 > - while countdown: > - link_st =3D subprocess.check_output("ip link show %s" % = intf, > - stderr=3Dsubprocess.ST= DOUT, > - shell=3DTrue) > - if "LOWER_UP" in link_st: > - break > - else: > - time.sleep(0.01) > - countdown -=3D 1 > - continue > - > - # fix fortville can't receive packets with 00:00:00:00:00:00 > - if self.pkt.getlayer(0).src =3D=3D "00:00:00:00:00:00": > - self.pkt.getlayer(0).src =3D get_if_hwaddr(intf) > - sendp(self.pkt, iface=3Dintf, count=3Dcount) > - > - # save command into test case history > - history_list =3D get_backtrace_object('test_case.py', 'test_= history') > - if type(history_list) is list: > - history_list.append({"command": "sendp(p, iface=3D\"%s\"= )" % intf, "name": > "Scapy", "output": ""}) >=20 > class Packet(object): >=20 > @@ -413,10 +346,11 @@ class Packet(object): > 'IPv6_SCTP': {'layers': ['ether', 'ipv6', 'sctp', 'raw'], 'cfglo= ad': True}, > } >=20 > - def __init__(self, **options): > + def __init__(self, pkt_str=3DNone, **options): > """ > pkt_type: description of packet type > defined in def_packet > + args: specify a packet with a string explicitly, will ignore > + options > options: special option for Packet module > pkt_len: length of network packet > ran_payload: whether payload of packet is random @@ -42= 4,14 +358,41 > @@ class Packet(object): > pkt_gen: packet generator type > now only support scapy > """ > - self.pkt_layers =3D [] > - self.pkt_len =3D 64 > self.pkt_opts =3D options > + self.pkt_layers =3D [] >=20 > - self.pkt_type =3D "UDP" > + if 'pkt_gen' in self.pkt_opts.keys(): > + if self.pkt_opts['pkt_gen'] =3D=3D 'scapy': > + self.pktgen =3D scapy() > + else: > + print "Not support other pktgen yet!!!" > + else: > + self.pktgen =3D scapy() >=20 > - if 'pkt_type' in self.pkt_opts.keys(): > - self.pkt_type =3D self.pkt_opts['pkt_type'] > + if pkt_str is not None and type(pkt_str) =3D=3D str: > + self._scapy_str_to_pkt(pkt_str) > + elif len(options) =3D=3D 0: > + pass > + else: > + self._add_pkt(self.pkt_opts) > + if self.pktgen.pkt is not None: > + self.pktgen.append_pkts() > + > + def __len__(self): > + return len(self.pktgen.pkts) > + > + def __getitem__(self, item): > + return self.pktgen.pkts[item] > + > + def _add_pkt(self, options): > + """ > + :param options: packt configuration, dictionary type > + :return: > + """ > + self.pkt_len =3D 64 > + self.pkt_type =3D "UDP" > + if 'pkt_type' in options.keys(): > + self.pkt_type =3D options['pkt_type'] >=20 > if self.pkt_type in self.def_packet.keys(): > self.pkt_layers =3D self.def_packet[self.pkt_type]['layers'] > @@ -441,21 +402,8 @@ class Packet(object): > else: > self._load_pkt_layers() >=20 > - if 'pkt_len' in self.pkt_opts.keys(): > - self.pkt_len =3D self.pkt_opts['pkt_len'] > - > - if 'pkt_file' in self.pkt_opts.keys(): > - self.uni_name =3D self.pkt_opts['pkt_file'] > - else: > - self.uni_name =3D '/tmp/' + str(uuid4()) + '.pcap' > - > - if 'pkt_gen' in self.pkt_opts.keys(): > - if self.pkt_opts['pkt_gen'] =3D=3D 'scapy': > - self.pktgen =3D scapy() > - else: > - print "Not support other pktgen yet!!!" > - else: > - self.pktgen =3D scapy() > + if 'pkt_len' in options.keys(): > + self.pkt_len =3D options['pkt_len'] >=20 > self._load_assign_layers() >=20 > @@ -483,32 +431,227 @@ class Packet(object): > raw_confs['payload'] =3D payload > self.config_layer('raw', raw_confs) >=20 > - def send_pkt(self, crb=3DNone, tx_port=3D'', auto_cfg=3DTrue, count= =3D1): > - if tx_port =3D=3D '': > - print "Invalid Tx interface" > - return > + def _scapy_str_to_pkt(self, scapy_str): > + """ >=20 > - self.tx_port =3D tx_port > + :param scapy_str: packet str, eg. 'Ether()/IP()/UDP()' > + :return: None > + """ > + layer_li =3D [re.sub('\(.*?\)', '', i) for i in scapy_str.split(= '/')] > + self.pkt_type =3D '_'.join(layer_li) > + self._load_pkt_layers() > + pkt =3D eval(scapy_str) > + self.pktgen.assign_pkt(pkt) >=20 > - # check with port type > - if 'ixia' in self.tx_port: > - print "Not Support Yet" > + def append_pkt(self, args=3DNone, **kwargs): > + """ > + :param args: take str type as pkt to append > + :param kwargs: take dictory type as pkt to append > + :return: None > + """ > + if isinstance(args, str): > + self._scapy_str_to_pkt(args) > + elif isinstance(kwargs, dict): > + self.pkt_opts =3D kwargs > + if hasattr(self, 'configured_layer_raw'): > + delattr(self, 'configured_layer_raw') > + self._add_pkt(kwargs) > + self.pktgen.append_pkts() > + > + def generate_random_pkts(self, dstmac=3DNone, pktnum=3D100, random_t= ype=3DNone, > ip_increase=3DTrue, random_payload=3DFalse, > + options=3DNone): > + """ > + # generate random packets > + :param dstmac: specify the dst mac > + :param pktnum: packet number to generate > + :param random_type: specify random packet type > + :param ip_increase: auto increase ip value > + :param random_payload: if True, generate random packets with ran= dom > payload > + :param options: packet layer configuration > + :return: None > + """ >=20 > - if crb is not None: > - self.pktgen.write_pcap(self.uni_name) > - crb.session.copy_file_to(self.uni_name) > - pcap_file =3D self.uni_name.split('/')[2] > - self.pktgen.send_pcap_pkt( > - crb=3Dcrb, file=3Dpcap_file, intf=3Dself.tx_port, count= =3Dcount) > + random_type =3D ['TCP', 'UDP', 'IPv6_TCP', 'IPv6_UDP'] if random= _type is None > else random_type > + options =3D {'ip': {'src': '192.168.0.1', 'dst': '192.168.1.1'}, > + 'layers_config': []} if options is None else options > + # give a default value to ip > + try: > + src_ip_num =3D convert_ip2int(options['ip']['src']) > + except: > + src_ip_num =3D 0 > + try: > + dst_ip_num =3D convert_ip2int(options['ip']['dst']) > + except: > + dst_ip_num =3D 0 > + > + for i in range(pktnum): > + # random the packet type > + self.pkt_type =3D random.choice(random_type) > + self.pkt_layers =3D self.def_packet[self.pkt_type]['layers'] > + self.check_layer_config() > + self.pktgen.add_layers(self.pkt_layers) > + # hardcode src/dst port for some protocol may cause issue > + if "TCP" in self.pkt_type: > + self.config_layer('tcp', {'src': 65535, 'dst': 65535}) > + if "UDP" in self.pkt_type: > + self.config_layer('udp', {'src': 65535, 'dst': 65535}) > + if options.has_key('layers_config'): > + self.config_layers(options['layers_config']) > + if dstmac: > + self.config_layer('ether', {'dst': '%s' % dstmac}) > + # generate auto increase dst ip packet > + if ip_increase: > + if 'v6' in self.pkt_type: > + dstip =3D convert_int2ip(dst_ip_num, ip_type=3D6) > + srcip =3D convert_int2ip(src_ip_num, ip_type=3D6) > + self.config_layer('ipv6', config=3D{'dst': '%s' % (d= stip), 'src': '%s' % srcip}) > + else: > + dstip =3D convert_int2ip(dst_ip_num, ip_type=3D4) > + srcip =3D convert_int2ip(src_ip_num, ip_type=3D4) > + self.config_layer('ipv4', config=3D{'dst': '%s' % (d= stip), 'src': '%s' % srcip}) > + dst_ip_num +=3D 1 > + # generate random payload of packet > + if random_payload and self.def_packet[self.pkt_type]['cfgloa= d']: > + # TCP packet has a default flags S, packet should not lo= ad data, so set it to A > if has payload > + if 'TCP' in self.pkt_type: > + self.config_layer('tcp', {'src': 65535, 'dst': > + 65535, 'flags': 'A'}) > + > + payload_len =3D random.randint(64, 100) > + payload =3D [] > + for _ in range(payload_len): > + payload.append("%02x" % random.randrange(0, 255)) > + self.config_layer('raw', config=3D{'payload': payload}) > + self.pktgen.append_pkts() > + > + def save_pcapfile(self, crb=3DNone, filename=3D'saved_pkts.pcap'): > + """ > + > + :param crb: session or crb object > + :param filename: location and name for packets to be saved > + :return: None > + """ > + # save pkts to pcap file to local path, then copy to remote test= er tmp directory, > + if crb: > + trans_path =3D crb.tmp_file > + file_name =3D filename > + if os.path.isabs(filename): # check if the given filename w= ith a abs path > + file_dir =3D os.path.dirname(filename) > + out =3D crb.send_expect('ls -d %s' % file_dir, '# ', ver= ify=3DTrue) > + if not isinstance(out, str): > + raise Exception('%s may not existed on %s' % (file_d= ir, crb.name)) > + wrpcap(filename, self.pktgen.pkts) > + trans_path =3D os.path.abspath(filename) > + file_name =3D filename.split(os.path.sep)[-1] > + # write packets to local tmp path $dts/ouput/tmp/pcap/ > + wrpcap(TMP_PATH + file_name, self.pktgen.pkts) > + # copy to remote tester tmp path /tmp/tester > + crb.session.copy_file_to(TMP_PATH + file_name, trans_path) > else: > - self.pktgen.send_pkt(intf=3Dself.tx_port, count=3Dcount) > + wrpcap(filename, self.pktgen.pkts) >=20 > - def check_layer_config(self, layer, config): > + def read_pcapfile(self, filename, crb=3DNone): > + """ > + > + :param filename: packet to be read from > + :param crb: session or crb object > + :return: scapy type packet > + """ > + # read pcap file from local or remote, then append to pkts list > + # if crb, read pakcet from remote server, else read from local l= ocation > + if crb: > + out =3D crb.send_expect('ls -d %s' % filename, '# ', verify= =3DTrue) > + if not isinstance(out, str): > + raise Exception('%s may not existed on %s' % (filename, = crb.name)) > + crb.session.copy_file_from(filename, TMP_PATH) > + p =3D rdpcap(TMP_PATH + filename.split(os.path.sep)[-1]) > + else: > + p =3D rdpcap(filename) > + if len(p) =3D=3D 0: > + return None > + self.pktgen.assign_pkt(p[-1]) > + for i in p: > + self.pktgen.pkts.append(i) > + return p > + > + def _send_pkt(self, crb, tx_port=3D'', count=3D1, send_bg=3DFalse, l= oop=3D0, inter=3D0, > timeout=3D15): > + """ > + > + :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 > + """ > + # save pkts to local pcap file, then copy to remote tester tmp > + directory > + > + time_stamp =3D str(time.time()) > + pcap_file =3D 'scapy_{}.pcap'.format(tx_port) + time_stamp > + self.save_pcapfile(crb, pcap_file) > + scapy_cmd =3D 'scapy_{}.cmd'.format(tx_port) + time_stamp > + cmd_str =3D 'from scapy.all import *\np=3Drdpcap("%s")\nprint("p= acket ready for > sending...")\nfor i in p:\n\tprint(i.command())\nsendp(p, iface=3D"%s", c= ount=3D%d, > loop=3D%d, inter=3D%0.3f)' % ( > + 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 a= ction > + session_prefix =3D 'scapy_bg_session' > + scapy_session =3D crb.create_session(session_prefix + time_s= tamp) > + scapy_session.send_command('python %s' % crb.tmp_file + scap= y_cmd) > + else: > + crb.send_expect('python %s' % crb.tmp_file + scapy_cmd, '# '= , > timeout=3Dtimeout) > + return crb.tmp_file + scapy_cmd > + > + def send_pkt(self, crb, tx_port=3D'', count=3D1, interval=3D0, timeo= ut=3D15): > + self._send_pkt(crb, tx_port, count, inter=3Dinterval, > + timeout=3Dtimeout) > + > + def send_pkt_bg(self, crb, tx_port=3D'', count=3D-1, loop=3D1, inter= val=3D0, timeout=3D3): > + return self._send_pkt(crb, tx_port=3Dtx_port, count=3Dcount, sen= d_bg=3DTrue, > loop=3Dloop, inter=3Dinterval, > + timeout=3Dtimeout) > + > + def stop_send_pkt_bg(self, crb, filenames): > + # stop sending action > + pids =3D [] > + if isinstance(filenames, list): > + for file in filenames: > + out =3D crb.send_expect('ps -ef |grep %s|grep -v grep' %= file, expected=3D'# ') > + try: > + pids.append(re.search('\d+', out).group()) > + except AttributeError as e: > + print(e, ' :%s not killed' % file) > + else: > + out =3D crb.send_expect('ps -ef |grep %s|grep -v grep' % fil= enames, expected=3D'# > ') > + try: > + pids.append(re.search('\d+', out).group()) > + except AttributeError as e: > + print(e, ' :%s not killed' % filenames) > + pid =3D ' '.join(pids) > + if pid: > + crb.send_expect('kill -9 %s' % pid, expected=3D'# ') > + for i in crb.sessions: > + if i.name.startswith('scapy_bg_session'): > + crb.destroy_session(i) > + > + def check_layer_config(self): > """ > check the format of layer configuration > every layer should has different check function > """ > - pass > + for layer in self.pkt_layers: > + found =3D False > + l_type =3D layer.lower() > + > + for types in LayersTypes.values(): > + if l_type in types: > + found =3D True > + break > + > + if found is False: > + self.pkt_layers.remove(l_type) > + print "INVAILD LAYER TYPE [%s]" % l_type.upper() >=20 > def assign_layers(self, layers=3DNone): > """ > @@ -532,6 +675,8 @@ class Packet(object): > print "INVAILD LAYER TYPE [%s]" % l_type.upper() >=20 > self.pktgen.add_layers(self.pkt_layers) > + if layers: > + self.pktgen.update_pkts() >=20 > def _load_pkt_layers(self): > name2type =3D { > @@ -590,9 +735,9 @@ class Packet(object): > else: > self.config_layer('raw', {'payload': ['00'] * 18}) >=20 > - if "MAC_IP_IPv6" in self.pkt_type or\ > - "MAC_IP_NVGRE" in self.pkt_type or \ > - "MAC_IP_UDP_VXLAN" in self.pkt_type: > + if "MAC_IP_IPv6" in self.pkt_type or \ > + "MAC_IP_NVGRE" in self.pkt_type or \ > + "MAC_IP_UDP_VXLAN" in self.pkt_type: > if "IPv6_SCTP" in self.pkt_type: > self.config_layer('ipv6', {'nh': 132}) > if "IPv6_ICMP" in self.pkt_type: > @@ -601,6 +746,8 @@ class Packet(object): > self.config_layer('raw', {'payload': ['00'] * 40}) > else: > self.config_layer('raw', {'payload': ['00'] * 18}) > + if 'TCP' in self.pkt_type: > + self.config_layer('tcp', {'flags': 0}) >=20 > def config_layer(self, layer, config=3D{}): > """ > @@ -613,22 +760,23 @@ class Packet(object): > print "INVALID LAYER ID %s" % layer > return False >=20 > - if self.check_layer_config(layer, config) is False: > + if self.check_layer_config() is False: > return False >=20 > if 'inner' in layer: > layer =3D layer[6:] >=20 > pkt_layer =3D self.pktgen.pkt.getlayer(idx) > - layer_conf =3D getattr(self, "_config_layer_%s" % layer) > + layer_conf =3D getattr(self.pktgen, layer) > setattr(self, 'configured_layer_%s' % layer, True) >=20 > - return layer_conf(pkt_layer, config) > + layer_conf(pkt_layer, **config) >=20 > def config_layers(self, layers=3DNone): > """ > Configure packet with multi configurations > """ > + layers =3D [] if layers is None else layers # None object is no= t > + Iterable > for layer in layers: > name, config =3D layer > if name not in self.pkt_layers: > @@ -638,65 +786,28 @@ class Packet(object): > print "[%s] failed to configure!!!" % name > raise >=20 > - def _config_layer_ether(self, pkt_layer, config): > - return self.pktgen.ether(pkt_layer, **config) > - > - def _config_layer_mac(self, pkt_layer, config): > - return self.pktgen.ether(pkt_layer, **config) > - > - def _config_layer_vlan(self, pkt_layer, config): > - return self.pktgen.vlan(pkt_layer, **config) > - > - def _config_layer_etag(self, pkt_layer, config): > - return self.pktgen.etag(pkt_layer, **config) > - > - def _config_layer_ipv4(self, pkt_layer, config): > - return self.pktgen.ipv4(pkt_layer, **config) > - > - def _config_layer_ipv6(self, pkt_layer, config): > - return self.pktgen.ipv6(pkt_layer, **config) > - > - def _config_layer_udp(self, pkt_layer, config): > - return self.pktgen.udp(pkt_layer, **config) > - > - def _config_layer_tcp(self, pkt_layer, config): > - return self.pktgen.tcp(pkt_layer, **config) > - > - def _config_layer_sctp(self, pkt_layer, config): > - return self.pktgen.sctp(pkt_layer, **config) > - > - def _config_layer_gre(self, pkt_layer, config): > - return self.pktgen.gre(pkt_layer, **config) > - > - def _config_layer_raw(self, pkt_layer, config): > - return self.pktgen.raw(pkt_layer, **config) > - > - def _config_layer_vxlan(self, pkt_layer, config): > - return self.pktgen.vxlan(pkt_layer, **config) > - > - def strip_layer_element(self, layer, element): > + def strip_layer_element(self, layer, element, p_index=3D0): > """ > Strip packet layer elements > return the status of configure result > """ > strip_element =3D getattr(self, "strip_element_%s" % layer) > + return strip_element(element, p_index) >=20 > - return strip_element(element) > - > - def strip_element_layer2(self, element): > - return self.pktgen.strip_layer2(element) > + def strip_element_layer2(self, element, p_index=3D0): > + return self.pktgen.strip_layer2(element, p_index) >=20 > - def strip_element_layer3(self, element): > - return self.pktgen.strip_layer3(element) > + def strip_element_layer3(self, element, p_index=3D0): > + return self.pktgen.strip_layer3(element, p_index) >=20 > - def strip_element_vlan(self, element): > - return self.pktgen.strip_vlan(element) > + def strip_element_vlan(self, element, p_index=3D0): > + return self.pktgen.strip_vlan(element, p_index) >=20 > - def strip_element_etag(self, element): > - return self.pktgen.strip_etag(element) > + def strip_element_etag(self, element, p_index=3D0): > + return self.pktgen.strip_etag(element, p_index) >=20 > - def strip_element_layer4(self, element): > - return self.pktgen.strip_layer4(element) > + def strip_element_layer4(self, element, p_index=3D0): > + return self.pktgen.strip_layer4(element, p_index) >=20 >=20 > def IncreaseIP(addr): > @@ -725,27 +836,6 @@ def IncreaseIPv6(addr): > return ipv6 >=20 >=20 > -def send_packets(intf, pkts=3DNone, interval=3D0.01): > - send_pkts =3D [] > - try: > - for pkt in pkts: > - send_pkts.append(pkt.pktgen.pkt) > - sendp(send_pkts, iface=3Dintf, inter=3Dinterval, verbose=3DFalse= ) > - except: > - pass > - > - > -def save_packets(pkts=3DNone, filename=3DNone): > - save_pkts =3D [] > - try: > - for pkt in pkts: > - save_pkts.append(pkt.pktgen.pkt) > - if filename: > - wrpcap(filename, save_pkts) > - except: > - pass > - > - > def get_ether_type(eth_type=3D""): > # need add more types later > if eth_type.lower() =3D=3D "lldp": > @@ -809,48 +899,46 @@ def get_filter_cmd(filters=3D[]): > return "" >=20 >=20 > -def sniff_packets(intf, count=3D0, timeout=3D5, filters=3D[], target=3D[= ]): > +def start_tcpdump(crb, intf, count=3D0, filters=3DNone, lldp_forbid=3DTr= ue): > """ > - sniff all packets for certain port in certain seconds > + sniff all packets from certain port > """ > + filters =3D [] if filters is None else filters > + out =3D crb.send_expect("ls -d %s" % crb.tmp_file, "# ", verify=3DTr= ue) > + if out =3D=3D 2: > + crb.send_expect("mkdir -p %s" % crb.tmp_file, "# ") > + filename =3D '{}sniff_{}.pcap'.format(crb.tmp_file, intf) > + # delete old pcap file > + crb.send_expect('rm -rf %s' % filename, '# ') > + > param =3D "" > direct_param =3D r"(\s+)\[ (\S+) in\|out\|inout \]" > - > - try: > - tcpdump_help_session=3Dpxssh.pxssh() > - tcpdump_help_session.login(server=3Dtarget[0], username=3Dtarget= [1], > - password=3Dtarget[2], original_prompt= =3D'[$#>]', > - login_timeout=3D20) > - tcpdump_help_session.sendline('tcpdump -h') > - tcpdump_help_session.prompt() > - tcpdump_help=3Dtcpdump_help_session.before > - tcpdump_help_session.logout() > - except pxssh.ExceptionPxssh as e: > - print ('pxssh failed on login.') > - print (e) > + tcpdump_session =3D crb.create_session('tcpdump_session' + str(time.= time())) > + setattr(tcpdump_session, 'tmp_file', crb.tmp_file) > + tcpdump_help =3D tcpdump_session.send_command('tcpdump -h') >=20 > for line in tcpdump_help.split('\n'): > m =3D re.match(direct_param, line) > if m: > - opt =3D re.search("-Q", m.group(2)); > + opt =3D re.search("-Q", m.group(2)) > if opt: > param =3D "-Q" + " in" > else: > - opt =3D re.search("-P", m.group(2)); > + opt =3D re.search("-P", m.group(2)) > if opt: > param =3D "-P" + " in" >=20 > if len(param) =3D=3D 0: > print "tcpdump not support direction choice!!!" >=20 > - if LLDP_FILTER not in filters: > + if lldp_forbid and (LLDP_FILTER not in filters): > filters.append(LLDP_FILTER) >=20 > filter_cmd =3D get_filter_cmd(filters) >=20 > sniff_cmd =3D 'tcpdump -i %(INTF)s %(FILTER)s %(IN_PARAM)s -w %(FILE= )s' > options =3D {'INTF': intf, 'COUNT': count, 'IN_PARAM': param, > - 'FILE': '/tmp/sniff_%s.pcap' % intf, > + 'FILE': filename, > 'FILTER': filter_cmd} > if count: > sniff_cmd +=3D ' -c %(COUNT)d' > @@ -858,77 +946,27 @@ def sniff_packets(intf, count=3D0, timeout=3D5, fil= ters=3D[], > target=3D[]): > else: > cmd =3D sniff_cmd % options >=20 > - try: > - tcpdump_session=3Dpxssh.pxssh() > - tcpdump_session.login(server=3Dtarget[0], username=3Dtarget[1], > - password=3Dtarget[2], original_prompt=3D'[= $#>]', > - login_timeout=3D20) > - tcpdump_session.sendline(cmd) > - pipe =3D tcpdump_session > - except pxssh.ExceptionPxssh as e: > - print ('pxssh failed on login.') > - print (e) > + tcpdump_session.send_command(cmd) >=20 > index =3D str(time.time()) > - SNIFF_PIDS[index] =3D (pipe, intf, timeout) > + SNIFF_PIDS[index] =3D (tcpdump_session, intf, filename) > time.sleep(1) > return index >=20 >=20 > -def load_sniff_pcap(index=3D'', target=3D[]): > +def stop_and_load_tcpdump_packets(index=3D'', timeout=3D1): > """ > - Stop sniffer and return pcap file > + Stop sniffer and return packet object > """ > - 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.prompt(timeout=3D1): > - child_exit =3D True > - break > - > - time_elapse +=3D 1 > - > - if not child_exit: > - try: > - # Stop Tcpdump on the target server > - tcpdump_quit_session=3Dpxssh.pxssh() > - tcpdump_quit_session.login(server=3Dtarget[0], username= =3Dtarget[1], > - password=3Dtarget[2], origina= l_prompt=3D'[$#>]', > - login_timeout=3D20) > - tcpdump_quit_session.sendline('kill -2 $(pidof tcpdump)'= ) > - tcpdump_quit_session.prompt() > - tcpdump_quit_session.logout() > - child_exit =3D True > - except pxssh.ExceptionPxssh as e: > - print ('pxssh failed on login.') > - print (e) > - > - # Close the Tcpdump_session > - pipe.prompt() > - pipe.logout() > - > - # wait pcap file ready > - time.sleep(1) > - return "/tmp/sniff_%s.pcap" % intf > - > - return "" > - > - > -def load_pcapfile(filename=3D""): > - pkts =3D [] > - try: > - cap_pkts =3D rdpcap(filename) > - for pkt in cap_pkts: > - # packet gen should be scapy > - packet =3D Packet() > - packet.pktgen.assign_pkt(pkt) > - pkts.append(packet) > - except: > - pass > - > - return pkts > + pipe, intf, filename =3D SNIFF_PIDS.pop(index) > + pipe.get_session_before(timeout) > + pipe.send_command('^C') > + pipe.copy_file_from(filename, TMP_PATH) > + p =3D Packet() > + p.read_pcapfile(TMP_PATH + filename.split(os.sep)[-1]) > + pipe.close() > + return p >=20 >=20 > def compare_pktload(pkt1=3DNone, pkt2=3DNone, layer=3D"L2"): > @@ -940,8 +978,8 @@ def compare_pktload(pkt1=3DNone, pkt2=3DNone, layer= =3D"L2"): > elif layer =3D=3D "L4": > l_idx =3D 2 > try: > - load1 =3D hexstr(str(pkt1.pktgen.pkt.getlayer(l_idx))) > - load2 =3D hexstr(str(pkt2.pktgen.pkt.getlayer(l_idx))) > + load1 =3D hexstr(str(pkt1.getlayer(l_idx))) > + load2 =3D hexstr(str(pkt2.getlayer(l_idx))) > except: > # return pass when scapy failed to extract packet > return True > @@ -952,7 +990,7 @@ def compare_pktload(pkt1=3DNone, pkt2=3DNone, layer= =3D"L2"): > return False >=20 >=20 > -def strip_pktload(pkt=3DNone, layer=3D"L2"): > +def strip_pktload(pkt=3DNone, layer=3D"L2", p_index=3D0): > if layer =3D=3D "L2": > l_idx =3D 0 > elif layer =3D=3D "L3": > @@ -962,30 +1000,36 @@ def strip_pktload(pkt=3DNone, layer=3D"L2"): > else: > l_idx =3D 0 > try: > - load =3D hexstr(str(pkt.pktgen.pkt.getlayer(l_idx)), onlyhex=3D1= ) > + load =3D hexstr(str(pkt.pktgen.pkts[p_index].getlayer(l_idx)), > + onlyhex=3D1) > except: > # return pass when scapy failed to extract packet > load =3D "" >=20 > return load >=20 > + >=20 > ########################################################### > #################### >=20 > ########################################################### > #################### > if __name__ =3D=3D "__main__": > - pkt =3D Packet(pkt_type=3D'UDP') > - pkt.send_pkt(tx_port=3D'lo') > + > + pkt =3D > Packet('Ether(type=3D0x894f)/NSH(Len=3D0x6,NextProto=3D0x0,NSP=3D0x000002= ,NSI=3D0xff > )') > + sendp(pkt, iface=3D'lo') > + pkt.config_layer('ipv4', {'dst': '192.168.8.8'}) > + pkt.append_pkt(pkt_type=3D'IPv6_TCP', pkt_len=3D100) > + pkt.append_pkt(pkt_type=3D'TCP', pkt_len=3D100) > + pkt.config_layer('tcp', config=3D{'flags': 'A'}) > + > pkt.append_pkt("Ether(dst=3D'11:22:33:44:55:11')/IP(dst=3D'192.168.5.2')/= TCP(flags=3D > 0)/Raw(load=3D'bbbb')") > + pkt.generate_random_pkts('11:22:33:44:55:55', random_type=3D['TCP', = 'IPv6_TCP'], > random_payload=3DTrue, pktnum=3D10) > + sendp(pkt, iface=3D'lo') >=20 > pkt =3D Packet(pkt_type=3D'UDP', pkt_len=3D1500, ran_payload=3DTrue) > - pkt.send_pkt(tx_port=3D'lo') > - pkt =3D Packet(pkt_type=3D'IPv6_TCP') > - pkt.send_pkt(tx_port=3D'lo') > + sendp(pkt, iface=3D'lo') > pkt =3D Packet(pkt_type=3D'IPv6_SCTP') > - pkt.send_pkt(tx_port=3D'lo') > + sendp(pkt, iface=3D'lo') > pkt =3D Packet(pkt_type=3D'VLAN_UDP') > pkt.config_layer('vlan', {'vlan': 2}) > - pkt.send_pkt(tx_port=3D'lo') > + sendp(pkt, iface=3D'lo') >=20 > - pkt =3D Packet() > pkt.assign_layers(['ether', 'vlan', 'ipv4', 'udp', > 'vxlan', 'inner_mac', 'inner_ipv4', 'inner_udp', = 'raw']) > pkt.config_layer('ether', {'dst': '00:11:22:33:44:55'}) @@ -994,13 += 1038,12 @@ if > __name__ =3D=3D "__main__": > pkt.config_layer('udp', {'src': 4789, 'dst': 4789, 'chksum': 0x1111}= ) > pkt.config_layer('vxlan', {'vni': 2}) > pkt.config_layer('raw', {'payload': ['58'] * 18}) > - pkt.send_pkt(tx_port=3D'lo') > + sendp(pkt, iface=3D'lo') >=20 > - pkt =3D Packet() > pkt.assign_layers(['ether', 'vlan', 'ipv4', 'udp', > 'vxlan', 'inner_mac', 'inner_ipv4', 'inner_udp', = 'raw']) > # config packet > pkt.config_layers([('ether', {'dst': '00:11:22:33:44:55'}), ('ipv4',= {'dst': '1.1.1.1'}), > ('vxlan', {'vni': 2}), ('raw', {'payload': ['01']= * 18})]) >=20 > - pkt.send_pkt(tx_port=3D'lo') > + sendp(pkt, iface=3D'lo') > -- > 2.17.1