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 490A74F93 for ; Thu, 28 Feb 2019 12:00:30 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 28 Feb 2019 03:00:29 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.58,423,1544515200"; d="scan'208";a="118443153" Received: from fmsmsx105.amr.corp.intel.com ([10.18.124.203]) by orsmga007.jf.intel.com with ESMTP; 28 Feb 2019 03:00:29 -0800 Received: from fmsmsx114.amr.corp.intel.com (10.18.116.8) by FMSMSX105.amr.corp.intel.com (10.18.124.203) with Microsoft SMTP Server (TLS) id 14.3.408.0; Thu, 28 Feb 2019 03:00:28 -0800 Received: from shsmsx105.ccr.corp.intel.com (10.239.4.158) by FMSMSX114.amr.corp.intel.com (10.18.116.8) with Microsoft SMTP Server (TLS) id 14.3.408.0; Thu, 28 Feb 2019 03:00:27 -0800 Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.158]) by SHSMSX105.ccr.corp.intel.com ([169.254.11.113]) with mapi id 14.03.0415.000; Thu, 28 Feb 2019 19:00:26 +0800 From: "Tu, Lijuan" To: "Mo, YufengX" , "dts@dpdk.org" CC: "Mo, YufengX" Thread-Topic: [dts] [PATCH V1]pmd_bonding: common methods used by bonding suites Thread-Index: AQHUzykTBp2SHdr3w02l2PjJavbWlKX1C0WQ Date: Thu, 28 Feb 2019 11:00:25 +0000 Message-ID: <8CE3E05A3F976642AAB0F4675D0AD20E0BA37BBD@SHSMSX101.ccr.corp.intel.com> References: <1551333007-33661-1-git-send-email-yufengx.mo@intel.com> <1551333007-33661-2-git-send-email-yufengx.mo@intel.com> In-Reply-To: <1551333007-33661-2-git-send-email-yufengx.mo@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.0.400.15 dlp-reaction: no-action x-ctpclassification: CTP_NT x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiOTYwZDBlYzktNTk3Yi00OTkyLWE5YmQtODI3YTgyNzYwYTZlIiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoicllsdFg5MncxU1g2QXZJQlZsTkR0UERhNFVhc3hMMXhrK2g4V2plOW1na0c2U2hPeUtkTTNPeG5KK2wyTlJuZCJ9 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]pmd_bonding: common methods used by bonding suites 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: Thu, 28 Feb 2019 11:00:31 -0000 .git/rebase-apply/patch:213: trailing whitespace. :param slaves: .git/rebase-apply/patch:273: trailing whitespace. rate_percent =3D kwargs.get('rate_percent', float(100)) .git/rebase-apply/patch:288: trailing whitespace. # run ixia testing .git/rebase-apply/patch:324: trailing whitespace. .git/rebase-apply/patch:326: trailing whitespace. warning: squelched 6 whitespace errors warning: 11 lines add whitespace errors. > -----Original Message----- > From: dts [mailto:dts-bounces@dpdk.org] On Behalf Of yufengmx > Sent: Thursday, February 28, 2019 1:50 PM > To: dts@dpdk.org > Cc: Mo, YufengX > Subject: [dts] [PATCH V1]pmd_bonding: common methods used by bonding > suites >=20 >=20 > It is a module that common methods are ran by > pmd_bonded_8023ad/pmd_stacked_bonded > suites, including: > boot up testpmd > sending packets > query testpmd information of ports > set testpmd port status > commond dpdk bonding commands >=20 > Signed-off-by: yufengmx > --- > tests/bonding.py | 831 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 831 insertions(+) > create mode 100644 tests/bonding.py >=20 > diff --git a/tests/bonding.py b/tests/bonding.py new file mode 100644 ind= ex > 0000000..fb2a69e > --- /dev/null > +++ b/tests/bonding.py > @@ -0,0 +1,831 @@ > +# 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. > + > +import os > +import time > +import re > +import struct > +import socket > +from socket import htonl > + > +from packet import Packet > +from scapy.sendrecv import sendp > +from scapy.utils import wrpcap > + > +import utils > +from exception import TimeoutException, VerifyFailure from pmd_output > +import PmdOutput from settings import HEADER_SIZE > + > +# define bonding mode > +MODE_ROUND_ROBIN =3D 0 > +MODE_ACTIVE_BACKUP =3D 1 > +MODE_XOR_BALANCE =3D 2 > +MODE_BROADCAST =3D 3 > +MODE_LACP =3D 4 > +MODE_TLB_BALANCE =3D 5 > +MODE_ALB_BALANCE =3D 6 > + > +# define packet size > +FRAME_SIZE_64 =3D 64 > +FRAME_SIZE_128 =3D 128 > +FRAME_SIZE_256 =3D 256 > +FRAME_SIZE_512 =3D 512 > +FRAME_SIZE_1024 =3D 1024 > +FRAME_SIZE_1518 =3D 1518 > + > +class PmdBonding(object): > + ''' common methods for testpmd bonding ''' > + > + def __init__(self, **kwargs): > + # set parent instance > + self.parent =3D kwargs.get('parent') > + # set target source code directory > + self.target_source =3D self.parent.dut.base_dir > + # set logger > + self.logger =3D self.parent.logger > + self.verify =3D self.parent.verify > + # select packet generator > + self.pktgen_name =3D 'ixia' if self.is_perf else 'scapy' > + # traffic default config > + self.default_pkt_size =3D kwargs.get('pkt_size') or FRAME_SIZE_6= 4 > + self.default_src_mac =3D kwargs.get('src_mac') > + self.default_src_ip =3D kwargs.get('src_ip') > + self.default_src_port =3D kwargs.get('src_port') > + self.default_dst_ip =3D kwargs.get('dst_ip') > + self.default_dst_port =3D kwargs.get('dst_port') > + self.default_pkt_name =3D kwargs.get('pkt_name') > + # testpmd > + self.testpmd =3D PmdOutput(self.parent.dut) > + self.testpmd_status =3D 'close' > + # > + # On tester platform, packet transmission > + # > + def mac_str_to_int(self, mac_str): > + """ convert the MAC type from the string into the int. """ > + mac_hex =3D '0x' > + for mac_part in mac_str.split(':'): > + mac_hex +=3D mac_part > + return int(mac_hex, 16) > + > + def mac_int_to_str(self, mac_int): > + """ Translate the MAC type from the string into the int. """ > + temp =3D hex(mac_int)[2:] > + b =3D [] > + [b.append(temp[n:n+2]) for n in range(len(temp)) if n % 2 =3D=3D= 0] > + new_mac =3D ":".join(b) > + return new_mac > + > + def ip_str_to_int(self, ip_str): > + """ > + convert the IP type from the string into the int. > + """ > + ip_int =3D socket.ntohl(struct.unpack( > + "I", socket.inet_aton(str(ip_str)))[0]) > + return ip_int > + > + def ip_int_to_str(self, ip_int): > + """ > + convert the IP type from the int into the string. > + """ > + ip_str =3D socket.inet_ntoa(struct.pack('I', socket.htonl(ip_int= ))) > + return ip_str > + > + def increase_ip(self, ip, step=3D1): > + ''' ip: string format ''' > + _ip_int =3D self.ip_str_to_int(ip) > + new_ip =3D self.ip_int_to_str(_ip_int + step) > + return new_ip > + > + def increase_mac(self, mac, step=3D1): > + ''' mac: string format ''' > + _mac_int =3D self.mac_str_to_int(mac) > + new_mac =3D self.mac_int_to_str(_mac_int+step) > + return new_mac > + > + def increase_port(self, port, step=3D1): > + ''' port: int format ''' > + new_port =3D port + step > + return new_port > + > + def increase_mac_ip_port(self, step=3D1): > + # get source port setting > + mac, ip, port =3D (self.default_src_mac, > + self.default_src_ip, > + self.default_src_port) > + return (self.increase_mac(mac, step), > + self.increase_ip(ip, step), > + self.increase_port(port, step)) > + > + def get_pkt_len(self, pkt_type): > + ''' get packet payload size ''' > + frame_size =3D self.default_pkt_size > + headers_size =3D sum(map(lambda x: HEADER_SIZE[x], > + ['eth', 'ip', pkt_type])) > + pktlen =3D frame_size - headers_size > + return pktlen > + > + def set_stream_to_slave_port(self, dut_port_id): > + ''' > + use framework/packet.py module to create one stream, send stream= to > + slave port > + ''' > + # get dst port mac address > + pkt_name =3D self.default_pkt_name > + destport =3D self.default_dst_port > + destip =3D self.default_dst_ip > + dst_mac =3D self.get_port_info(dut_port_id, 'mac') > + # packet size > + pktlen =3D self.get_pkt_len(pkt_name) > + # set stream configuration > + srcmac, srcip, srcport =3D self.increase_mac_ip_port(0) > + pkt_config =3D { > + 'type': pkt_name.upper(), > + 'pkt_layers': { > + # Ether(dst=3Dnutmac, src=3Dsrcmac) > + 'ether': {'src': srcmac, 'dst': dst_mac}, > + # IP(dst=3Ddestip, src=3Dsrcip, len=3D%s) > + 'ipv4': {'src': srcip, 'dst': destip}, > + # pkt_name(sport=3Dsrcport, dport=3Ddestport) > + pkt_name: {'src': srcport, 'dst': destport}, > + # Raw(load=3D'\x50'*%s) > + 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}} > + # create packet > + streams =3D [] > + # keep a copy of pcap for debug > + savePath =3D os.sep.join([self.target_source, > + "pkt_{0}.pcap".format(pkt_name)]) > + pkt_type =3D pkt_config.get('type') > + pkt_layers =3D pkt_config.get('pkt_layers') > + pkt =3D Packet(pkt_type=3Dpkt_type.upper()) > + for layer in pkt_layers.keys(): > + pkt.config_layer(layer, pkt_layers[layer]) > + pkt.pktgen.write_pcap(savePath) > + streams.append(pkt.pktgen.pkt) > + > + return streams > + > + def set_stream_to_bond_port(self, bond_port, slaves): > + ''' > + : use framework/packet.py module to create multiple streams > + send streams from bond port to slaves > + :param bond_port: > + bonded device port id > + :param slaves: > + slaves port id > + ''' > + pkt_configs =3D [] > + # get dst port mac address > + pkt_name =3D self.default_pkt_name > + destport =3D self.default_dst_port > + destip =3D self.default_dst_ip > + dst_mac =3D self.get_port_info(bond_port, 'mac') > + # packet size > + pktlen =3D self.get_pkt_len(pkt_type) > + # set stream configuration > + for packet_id in range(len(slaves['active'])): > + srcmac, srcip, srcport =3D self.increase_mac_ip_port(packet_= id) > + pkt_configs.append({ > + 'type': pkt_name.upper(), > + 'pkt_layers': { > + # Ether(dst=3Dnutmac, src=3Dsrcmac) > + 'ether': {'src': srcmac, 'dst': dst_mac}, > + # IP(dst=3Ddestip, src=3Dsrcip, len=3D%s) > + 'ipv4': {'src': srcip, 'dst': destip}, > + # pkt_name(sport=3Dsrcport, dport=3Ddestport) > + pkt_name: {'src': srcport, 'dst': destport}, > + # Raw(load=3D'\x50'*%s) > + 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}= }) > + # create packet > + streams =3D [] > + for values in pkt_configs: > + # keep a copy of pcap for debug > + savePath =3D os.sep.join([self.target_source, > + "pkt_{0}.pcap".format(stm_name)]) > + pkt_type =3D values.get('type') > + pkt_layers =3D values.get('pkt_layers') > + pkt =3D Packet(pkt_type=3Dpkt_type.upper()) > + for layer in pkt_layers.keys(): > + pkt.config_layer(layer, pkt_layers[layer]) > + pkt.pktgen.write_pcap(savePath) > + streams.append(pkt.pktgen.pkt) > + > + return streams > + > + def send_packets_by_scapy(self, **kwargs): > + tx_iface =3D kwargs.get('port topo')[0] > + # set interface ready to send packet > + cmd =3D "ifconfig {0} up".format(tx_iface) > + self.parent.tester.send_expect(cmd, '# ', 30) > + send_pkts =3D kwargs.get('stream') > + # stream config > + stream_configs =3D kwargs.get('traffic configs') > + count =3D stream_configs.get('count') > + interval =3D stream_configs.get('interval', 0.01) > + # run traffic > + sendp(send_pkts, iface=3Dtx_iface, inter=3Dinterval, verbose=3DF= alse, > + count=3Dcount) > + > + def send_packets_by_ixia(self, **kwargs): > + tester_port =3D kwargs.get('tx_intf') > + count =3D kwargs.get('count', 1) > + traffic_type =3D kwargs.get('traffic_type', 'normal') > + traffic_time =3D kwargs.get('traffic_time', 0) > + rate_percent =3D kwargs.get('rate_percent', float(100)) > + #--------------------------------------------------------------- > + send_pkts =3D [] > + self.tgen_input =3D [] > + tgen_input =3D self.tgen_input > + # generate packet contain multi stream > + for pkt in self.packet_types.values(): > + send_pkts.append(pkt.pktgen.pkt) > + ixia_pkt =3D os.sep.join([self.target_source, 'bonding_ixia.pcap= ']) > + wrpcap(ixia_pkt, send_pkts) > + #---------------------------------------------------------------= - > + # set packet for send > + # pause frame basic configuration > + pause_time =3D 65535 > + pause_rate =3D 0.50 > + # run ixia testing > + frame_size =3D self.default_pkt_size > + # calculate number of packets > + expect_pps =3D self.parent.wirespeed(self.parent.nic, frame_size= , 1) * \ > + 1000= 000.0 > + # get line rate > + linerate =3D expect_pps * (frame_size + 20) * 8 > + # calculate default sleep time for one pause frame > + sleep =3D (1 / linerate) * pause_time * 512 > + # calculate packets dropped in sleep time > + self.n_pkts =3D int((sleep / (1 / expect_pps)) * (1 / pause_rate= )) > + #---------------------------------------------------------------= - > + tester_port =3D self.parent.tester.get_local_port(self.parent.du= t_ports[0]) > + tgen_input.append((tester_port, tester_port,ixia_pkt)) > + # run latency stat statistics > + self.parent.tester.loop_traffic_generator_throughput(tgen_input, > + > + self.rate_percent) > + > + def stop_ixia(self, data_types=3D'packets'): > + tester_inst =3D self.parent.tester > + # get ixia statistics > + line_rate =3D tester_inst.get_port_line_rate() > + rx_bps, rx_pps =3D \ > + tester_inst.stop_traffic_generator_throughput_loop(self.tgen= _input) > + output =3D tester_inst.traffic_get_port_stats(self.tgen_input) > + self.cur_data['ixia statistics'] =3D [] > + append =3D self.cur_data['ixia statistics'].append > + append('send packets: {0}'.format(output[0])) > + append('line_rate: {0}'.format(line_rate[0])) > + append('rate_percent: {0}%'.format(self.rate_percent)) > + > + def get_pktgen(self, name): > + pkt_gens =3D { > + 'ixia': self.send_packets_by_ixia, > + 'scapy': self.send_packets_by_scapy,} > + pkt_generator =3D pkt_gens.get(name) > + > + return pkt_generator > + > + def send_packet(self, traffic_config): > + """ > + stream transmission on specified link topology > + """ > + time.sleep(2) > + # start traffic > + self.logger.info("begin transmission ...") > + pktgen =3D self.get_pktgen(self.pktgen_name) > + result =3D pktgen(**traffic_config) > + # end traffic > + self.logger.info("complete transmission") > + > + return result > + # > + # On dut, dpdk testpmd common methods > + # > + def check_process_status(self, process_name=3D'testpmd'): > + cmd =3D "ps aux | grep -i %s | grep -v grep | awk {'print $2'}"%= ( > + process_= name) > + out =3D self.parent.dut.alt_session.send_expect(cmd, "# ", 10) > + status =3D True if out !=3D "" else False > + return status > + > + def check_process_exist(self, process_name=3D'testpmd'): > + status =3D self.check_process_status(process_name) > + if not status: > + msg =3D "{0} process exceptional quit".format(process_name) > + out =3D self.parent.dut.session.session.get_output_all() > + self.logger.info(out) > + raise VerifyFailure(msg) > + > + def d_console(self, cmds): > + ''' wrap up testpmd command interactive console ''' > + if len(cmds) =3D=3D 0: > + return > + # check if cmds is string > + if isinstance(cmds, str): > + timeout =3D 10 > + cmds =3D [[cmds, '', timeout]] > + # check if cmds is only one command > + if not isinstance(cmds[0], list): > + cmds =3D [cmds] > + outputs =3D [] if len(cmds) > 1 else '' > + for item in cmds: > + expected_items =3D item[1] > + if expected_items and isinstance(expected_items, (list, tupl= e)): > + check_output =3D True > + expected_str =3D expected_items[0] or 'testpmd> ' > + else: > + check_output =3D False > + expected_str =3D expected_items or 'testpmd> ' > + timeout =3D int(item[2]) if len(item) =3D=3D 3 else 5 > + #-----------------------------------------------------------= ----- > + # run command on session > + try: > + console =3D self.testpmd.execute_cmd > + msg_pipe =3D self.testpmd.get_output > + output =3D console(item[0], expected_str, timeout) > + output =3D msg_pipe(timeout) if not output else output > + except TimeoutException: > + try: > + # check if testpmd quit > + self.check_process_exist() > + except Exception as e: > + self.testpmd_status =3D 'close' > + msg =3D "execute '{0}' timeout".format(item[0]) > + output =3D out =3D self.parent.dut.session.session.get_o= utput_all() > + self.logger.error(output) > + raise Exception(msg) > + > + if len(cmds) > 1: > + outputs.append(output) > + else: > + outputs =3D output > + if check_output and len(expected_items) >=3D 2: > + self.logger.info(output) > + expected_output =3D expected_items[1] > + check_type =3D True if len(expected_items) =3D=3D 2 \ > + else expected_items[2] > + if check_type and expected_output in output: > + msg =3D "expected '{0}' is in output".format(expecte= d_output) > + self.logger.info(msg) > + elif not check_type and expected_output not in output: > + fmt =3D "unexpected '{0}' is not in output" > + msg =3D fmt.format(expected_output) > + self.logger.info(msg) > + else: > + status =3D "isn't in" if check_type else "is in" > + msg =3D "[{0}] {1} output".format(expected_output, s= tatus) > + self.logger.error(msg) > + raise VerifyFailure(msg) > + > + time.sleep(2) > + return outputs > + > + def preset_testpmd(self, core_mask, options=3D'', eal_param=3D''): > + try: > + self.testpmd.start_testpmd( core_mask, > + param=3D' '.join(options), > + eal_param=3Deal_param) > + except TimeoutException: > + # check if testpmd quit > + try: > + self.check_process_exist() > + except Exception as e: > + self.testpmd_status =3D 'close' > + msg =3D "execute '{0}' timeout".format(item[0]) > + self.logger.error(msg_pipe(timeout)) > + raise TimeoutException(msg) > + # wait lsc event udpate done > + time.sleep(10) > + # check if testpmd has bootep up > + if self.check_process_status(): > + self.logger.info("testpmd boot up successful") > + else: > + raise VerifyFailure("testpmd boot up failed") > + self.d_console(self.preset_testpmd_cmds) > + self.preset_testpmd_cmds =3D [] > + time.sleep(1) > + > + def start_testpmd(self, eal_option=3D''): > + if self.testpmd_status =3D=3D 'running': > + return > + # boot up testpmd > + hw_mask =3D 'all' > + options =3D '' > + self.preset_testpmd_cmds =3D ['port stop all', '', 15] > + self.preset_testpmd(hw_mask, options, eal_param=3Deal_option) > + self.testpmd_status =3D 'running' > + > + def stop_testpmd(self): > + time.sleep(1) > + testpmd_cmds =3D[['port stop all', '', 15], > + ['show port stats all', ''], > + ['stop', ''],] > + output =3D self.d_console(testpmd_cmds) > + time.sleep(1) > + return output > + > + def close_testpmd(self): > + if self.testpmd_status =3D=3D 'close': > + return None > + output =3D self.stop_testpmd() > + time.sleep(1) > + self.testpmd.quit() > + time.sleep(10) > + if self.check_process_status(): > + raise VerifyFailure("testpmd close failed") > + else: > + self.logger.info("close testpmd successful") > + self.testpmd_status =3D 'close' > + return output > + > + def start_ports(self, port=3D'all'): > + """ > + Start a port which the testpmd can see. > + """ > + timeout =3D 12 if port=3D=3D'all' else 5 > + cmds =3D[ > + ["port start %s" % str(port), " ", timeout], > + # to avoid lsc event message interfere normal status > + [" ", '', timeout]] > + self.d_console(cmds) > + > + def get_stats(self, portid, flow=3D['rx', 'tx']): > + """ > + get one port statistics of testpmd > + """ > + _portid =3D int(portid) if isinstance(portid, (str, unicode)) el= se portid > + info =3D self.testpmd.get_pmd_stats(_portid) > + _kwd =3D ["-packets", "-errors", "-bytes"] > + stats =3D {} > + if isinstance(flow, list): > + for item in flow: > + for item2 in _kwd: > + name =3D item.upper() + item2 > + stats[name] =3D int(info[name]) > + elif isinstance(flow, (str, unicode)): > + for item in _kwd: > + name =3D flow.upper() + item > + stats[name] =3D int(info[name]) > + else: > + msg =3D 'unknown data type' > + raise Exception(msg) > + > + return stats > + > + def get_all_stats(self, ports): > + """ > + Get a group of ports statistics, which testpmd can display. > + """ > + stats =3D {} > + attrs =3D ['tx', 'rx'] > + for port_id in ports: > + stats[port_id] =3D self.get_stats(port_id, attrs) > + > + return stats > + > + def set_tester_port_status(self, port_name, status): > + """ > + Do some operations to the network interface port, > + such as "up" or "down". > + """ > + eth =3D self.parent.tester.get_interface(port_name) > + self.parent.tester.admin_ports_linux(eth, status) > + time.sleep(5) > + > + def set_dut_peer_port_by_id(self, port_id, status): > + # stop peer port on tester > + intf =3D self.parent.tester.get_local_port(self.parent.dut_ports= [port_id]) > + self.set_tester_port_status(intf, status) > + time.sleep(5) > + cur_status =3D self.get_port_info(port_id, 'link_status') > + self.logger.info("port {0} is [{1}]".format(port_id, cur_status)= ) > + if cur_status !=3D status: > + self.logger.warning("expected status is > + [{0}]".format(status)) > + > + def set_dut_port_status(self, port_id, status): > + opt =3D 'link-up' if status =3D=3D 'up' else 'link-down' > + # stop slave link by force > + cmd =3D "set {0} port {1}".format(opt, port_id) > + self.d_console(cmd) > + time.sleep(5) > + cur_status =3D self.get_port_info(port_id, 'link_status') > + self.logger.info("port {0} is [{1}]".format(port_id, cur_status)= ) > + if cur_status !=3D status: > + self.logger.warning("expected status is [{0}]".format(status= )) > + # > + # testpmd bonding commands > + # > + def get_value_from_str(self, key_str, regx_str, string): > + """ > + Get some values from the given string by the regular expression. > + """ > + if isinstance(key_str, (unicode, str)): > + pattern =3D r"(?<=3D%s)%s" % (key_str, regx_str) > + s =3D re.compile(pattern) > + res =3D s.search(string) > + if type(res).__name__ =3D=3D 'NoneType': > + msg =3D "{0} hasn't match anything".format(key_str) > + self.logger.warning(msg) > + return ' ' > + else: > + return res.group(0) > + elif isinstance(key_str, (list, tuple)): > + for key in key_str: > + pattern =3D r"(?<=3D%s)%s" % (key, regx_str) > + s =3D re.compile(pattern) > + res =3D s.search(string) > + if type(res).__name__ =3D=3D 'NoneType': > + continue > + else: > + return res.group(0) > + else: > + self.logger.warning("all key_str hasn't match anything") > + return ' ' > + > + def _get_detail_from_port_info(self, port_id, args): > + """ > + Get the detail info from the output of pmd cmd > + 'show port info '. > + """ > + key_str, regx_str =3D args > + out =3D self.d_console("show port info %d" % port_id) > + find_value =3D self.get_value_from_str(key_str, regx_str, out) > + return find_value > + > + def get_detail_from_port_info(self, port_id, args): > + if isinstance(args[0], (list, tuple)): > + return [self._get_detail_from_port_info(port_id, sub_args) > + for sub_args in args] > + else: > + return self._get_detail_from_port_info(port_id, args) > + > + def get_port_info(self, port_id, info_type): > + ''' > + Get the specified port information by its output message format > + ''' > + info_set =3D { > + 'mac': ["MAC address: ", "([0-9A-F]{2}:){5}[0-9A-F]= {2}"], > + 'connect_socket': ["Connect to socket: ", "\d+"], > + 'memory_socket': ["memory allocation on the socket: ", "\d+"]= , > + 'link_status': ["Link status: ", "\S+"], > + 'link_speed': ["Link speed: ", "\d+"], > + 'link_duplex': ["Link duplex: ", "\S+"], > + 'promiscuous_mode': ["Promiscuous mode: ", "\S+"], > + 'allmulticast_mode':["Allmulticast mode: ", "\S+"], > + 'vlan_offload': [ > + ["strip ", "\S+"], > + ['filter', "\S+"], > + ['qinq\(extend\) ', "\S+"]], > + 'queue_config': [ > + ["Max possible RX queues: ", "\d+"], > + ['Max possible number of RXDs per queue: ', "\d+= "], > + ['Min possible number of RXDs per queue: ', "\d+= "], > + ["Max possible TX queues: ", "\d+"], > + ['Max possible number of TXDs per queue: ', "\d+= "], > + ['Min possible number of TXDs per queue: ', "\d+= "],] > + } > + > + if info_type in info_set.keys(): > + return self.get_detail_from_port_info(port_id, info_set[info= _type]) > + else: > + msg =3D os.linesep.join([ > + "support query items including::", > + os.linesep.join(info_set.keys())]) > + self.logger.warning(msg) > + return None > + # > + # On dut, dpdk testpmd common bonding methods > + # > + def get_bonding_config(self, config_content, args): > + """ > + Get bonding info by command "show bonding config". > + """ > + key_str, regx_str =3D args > + find_value =3D self.get_value_from_str(key_str, regx_str, config= _content) > + return find_value > + > + def get_info_from_bond_config(self, config_content, args): > + """ > + Get active slaves of the bonding device which you choose. > + """ > + search_args =3D args if isinstance(args[0], (list, tuple)) else = [args] > + for search_args in search_args: > + try: > + info =3D self.get_bonding_config(config_content, search_= args) > + break > + except Exception as e: > + self.logger.info(e) > + else: > + info =3D None > + > + return info > + > + def get_bonding_info(self, bond_port, info_types): > + ''' Get the specified port information by its output message for= mat ''' > + info_set =3D { > + 'mode': ["Bonding mode: ", "\d*"], > + 'agg_mode': ["IEEE802.3AD Aggregator Mode: ", "\S*"], > + 'balance_policy':["Balance Xmit Policy: ", "\S+"], > + 'slaves': [["Slaves \(\d\): \[", "\d*( \d*)*"], > + ["Slaves: \[", "\d*( \d*)*"]], > + 'active_slaves': [["Active Slaves \(\d\): \[", "\d*( \d*)*"]= , > + ["Acitve Slaves: \[", "\d*( \d*)*"]], > + 'primary': ["Primary: \[", "\d*"]} > + # get all config information > + config_content =3D self.d_console("show bonding config %d" % bon= d_port) > + if isinstance(info_types, (list or tuple)): > + query_values =3D [] > + for info_type in info_types: > + if info_type in info_set.keys(): > + find_value =3D self.get_info_from_bond_config( > + config_content, info_set[inf= o_type]) > + if info_type in ['active_slaves', 'slaves']: > + find_value =3D [value for value in find_value.sp= lit(' ') > + if value] > + else: > + find_value =3D None > + query_values.append(find_value) > + return query_values > + else: > + info_type =3D info_types > + if info_type in info_set.keys(): > + find_value =3D self.get_info_from_bond_config( > + config_content, info_set[inf= o_type]) > + if info_type in ['active_slaves', 'slaves']: > + find_value =3D [value for value in find_value.split(= ' ') > + if value] > + return find_value > + else: > + return None > + > + def get_active_slaves(self, bond_port): > + primary_port =3D int(self.get_bonding_info(bond_port, 'primary')= ) > + active_slaves =3D self.get_bonding_info(bond_port, > + 'active_slaves') > + > + return int(primary_port), [int(slave) for slave in > + active_slaves] > + > + def create_bonded_device(self, mode=3D0, socket=3D0, verify_detail= =3DFalse): > + """ > + Create a bonding device with the parameters you specified. > + """ > + cmd =3D "create bonded device %d %d" % (mode, socket) > + out =3D self.d_console(cmd) > + err_fmt =3D "Create bonded device on mode [%d] socket [%d] faile= d" > + self.verify("Created new bonded device" in out, err_fmt% (mode, = socket)) > + fmts =3D [ > + "Created new bonded device net_bond_testpmd_[\d] on \(port = ", > + "Created new bonded device net_bonding_testpmd_[\d] on \(po= rt ", > + "Created new bonded device eth_bond_testpmd_[\d] on \(port = "] > + bond_port =3D self.get_value_from_str(fmts, "\d+", out) > + bond_port =3D int(bond_port) > + > + if verify_detail: > + out =3D self.d_console("show bonding config %d" % bond_port) > + self.verify("Bonding mode: %d" % mode in out, > + "Bonding mode display error when create bonded d= evice") > + self.verify("Slaves: []" in out, > + "Slaves display error when create bonded device"= ) > + self.verify("Active Slaves: []" in out, > + "Active Slaves display error when create bonded = device") > + self.verify("Primary: []" not in out, > + "Primary display error when create bonded device= ") > + out =3D self.d_console("show port info %d" % bond_port) > + self.verify("Connect to socket: %d" % socket in out, > + "Bonding port connect socket error") > + self.verify("Link status: down" in out, > + "Bonding port default link status error") > + self.verify("Link speed: 0 Mbps" in out, > + "Bonding port default link speed error") > + > + return bond_port > + > + def add_slave(self, bond_port, invert_verify=3DFalse, expected_str= =3D'', > + *slave_ports): > + """ > + Add ports into the bonding device as slaves. > + """ > + if len(slave_ports) <=3D 0: > + utils.RED("No port exist when add slave to bonded device") > + for slave_id in slave_ports: > + cmd =3D "add bonding slave %d %d" % (slave_id, bond_port) > + out =3D self.d_console(cmd) > + if expected_str: > + self.verify(expected_str in out, > + "message <{0}> is missing".format(expected_s= tr)) > + slaves =3D self.get_bonding_info(bond_port, 'slaves') > + if not invert_verify: > + self.verify(str(slave_id) in slaves, > + "Add port as bonding slave failed") > + else: > + err =3D "Add port as bonding slave successfully,should f= ail" > + self.verify(str(slave_id) not in slaves, err) > + > + def remove_slaves(self, bond_port, invert_verify=3DFalse, *slave_por= t): > + """ > + Remove the specified slave port from the bonding device. > + """ > + if len(slave_port) <=3D 0: > + msg =3D "No port exist when remove slave from bonded device" > + self.logger.error(msg) > + for slave_id in slave_port: > + cmd =3D "remove bonding slave %d %d" % (int(slave_id), bond_= port) > + self.d_console(cmd) > + slaves =3D self.get_bonding_info(bond_port, 'slaves') > + if not invert_verify: > + self.verify(str(slave_id) not in slaves, > + "Remove slave to fail from bonding device") > + else: > + err =3D ( > + "Remove slave successfully from bonding device, " > + "should be failed") > + self.verify(str(slave_id) in slaves, err) > + > + def remove_all_slaves(self, bond_port): > + """ > + Remove all slaves of specified bound device. > + """ > + all_slaves =3D self.get_bonding_info(bond_port, 'slaves') > + if not all_slaves: > + return > + all_slaves =3D all_slaves.split() > + if len(all_slaves) =3D=3D 0: > + return > + self.remove_slaves(bond_port, False, *all_slaves) > + > + def set_primary_slave(self, bond_port, slave_port, invert_verify=3DF= alse): > + """ > + Set the primary slave for the bonding device. > + """ > + cmd =3D "set bonding primary %d %d" % (slave_port, bond_port) > + self.d_console(cmd) > + out =3D self.get_bonding_info(bond_port, 'primary') > + if not invert_verify: > + self.verify(str(slave_port) in out, > + "Set bonding primary port failed") > + else: > + err =3D "Set bonding primary port successfully, should not s= uccess" > + self.verify(str(slave_port) not in out, err) > + > + def set_bonding_mode(self, bond_port, mode): > + """ > + Set the bonding mode for port_id. > + """ > + cmd =3D "set bonding mode %d %d" % (mode, bond_port) > + self.d_console(cmd) > + mode_value =3D self.get_bonding_info(bond_port, 'mode') > + self.verify(str(mode) in mode_value, "Set bonding mode failed") > + > + def set_bonding_mac(self, bond_port, mac): > + """ > + Set the MAC for the bonding device. > + """ > + cmd =3D "set bonding mac_addr %s %s" % (bond_port, mac) > + self.d_console(cmd) > + new_mac =3D self.get_port_mac(bond_port) > + self.verify(new_mac =3D=3D mac, "Set bonding mac failed") > + > + def get_port_mac(self, bond_port, query_type): > + bond_port_mac =3D self.get_port_info(bond_port, query_type) > + return bond_port_mac > + > + def set_bonding_balance_policy(self, bond_port, policy): > + """ > + Set the balance transmit policy for the bonding device. > + """ > + cmd =3D "set bonding balance_xmit_policy %d %s" % (bond_port, po= licy) > + self.d_console(cmd) > + new_policy =3D self.get_bonding_info(bond_port, 'balance_policy'= ) > + policy =3D "BALANCE_XMIT_POLICY_LAYER" + policy.lstrip('l') > + self.verify(new_policy =3D=3D policy, "Set bonding balance polic= y > + failed") > + > + @property > + def is_perf(self): > + return self.parent._enable_perf > -- > 1.9.3