From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id 5F0174F94 for ; Thu, 28 Feb 2019 09:40:33 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 28 Feb 2019 00:40:32 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.58,422,1544515200"; d="scan'208";a="119747916" Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201]) by orsmga006.jf.intel.com with ESMTP; 28 Feb 2019 00:40:31 -0800 Received: from fmsmsx117.amr.corp.intel.com (10.18.116.17) by FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS) id 14.3.408.0; Thu, 28 Feb 2019 00:40:31 -0800 Received: from shsmsx153.ccr.corp.intel.com (10.239.6.53) by fmsmsx117.amr.corp.intel.com (10.18.116.17) with Microsoft SMTP Server (TLS) id 14.3.408.0; Thu, 28 Feb 2019 00:40:30 -0800 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.74]) by SHSMSX153.ccr.corp.intel.com ([169.254.12.121]) with mapi id 14.03.0415.000; Thu, 28 Feb 2019 16:40:29 +0800 From: "Chen, Zhaoyan" To: "Mo, YufengX" , "dts@dpdk.org" CC: "Mo, YufengX" , "Chen, Zhaoyan" Thread-Topic: [dts] [PATCH V1]pmd_bonding: common methods used by bonding suites Thread-Index: AQHUzykSefroTb5SPEWVC+yBt5a636X0MlgAgACx0rA= Date: Thu, 28 Feb 2019 08:40:28 +0000 Message-ID: <9DEEADBC57E43F4DA73B571777FECECA41C5A177@SHSMSX104.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: 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-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 08:40:34 -0000 Acked-by: Chen, Zhaoyan Regards, Zhaoyan Chen > -----Original Message----- > From: dts [mailto:dts-bounces@dpdk.org] On Behalf Of Mo, YufengX > Sent: Thursday, February 28, 2019 2:04 PM > To: dts@dpdk.org > Cc: Mo, YufengX > Subject: Re: [dts] [PATCH V1]pmd_bonding: common methods used by bonding > suites >=20 >=20 > Tested-by: Mo, YufengX >=20 > > -----Original Message----- > > From: Mo, YufengX > > 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 > > > > > > 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 > > > > Signed-off-by: yufengmx > > --- > > tests/bonding.py | 831 > > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > > 1 file changed, 831 insertions(+) > > create mode 100644 tests/bonding.py > > > > diff --git a/tests/bonding.py b/tests/bonding.py new file mode 100644 > > index 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 copyrigh= t > > +# 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= _64 > > + 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_i= nt))) > > + 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 stre= am 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(packe= t_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= =3DFalse, > > + 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.pc= ap']) > > + 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_si= ze, 1) * \ > > + 10= 00000.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_ra= te)) > > + #-------------------------------------------------------------= --- > > + tester_port =3D self.parent.tester.get_local_port(self.parent.= dut_ports[0]) > > + tgen_input.append((tester_port, tester_port,ixia_pkt)) > > + # run latency stat statistics > > + self.parent.tester.loop_traffic_generator_throughput(tgen_inpu= t, > > + > > + 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.tg= en_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'}= "%( > > + proces= s_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, tu= ple)): > > + 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= _output_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(expec= ted_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,= status) > > + 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)) = else 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_por= ts[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_statu= s)) > > + 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_statu= s)) > > + if cur_status !=3D status: > > + self.logger.warning("expected status is [{0}]".format(stat= us)) > > + # > > + # testpmd bonding commands > > + # > > + def get_value_from_str(self, key_str, regx_str, string): > > + """ > > + Get some values from the given string by the regular expressio= n. > > + """ > > + 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 forma= t > > + ''' > > + 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[in= fo_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, conf= ig_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)) els= e [args] > > + for search_args in search_args: > > + try: > > + info =3D self.get_bonding_config(config_content, searc= h_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 f= ormat ''' > > + 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" % b= ond_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[i= nfo_type]) > > + if info_type in ['active_slaves', 'slaves']: > > + find_value =3D [value for value in find_value.= split(' ') > > + 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[i= nfo_type]) > > + if info_type in ['active_slaves', 'slaves']: > > + find_value =3D [value for value in find_value.spli= t(' ') > > + 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] fai= led" > > + self.verify("Created new bonded device" in out, err_fmt% (mode= , socket)) > > + fmts =3D [ > > + "Created new bonded device net_bond_testpmd_[\d] on \(por= t ", > > + "Created new bonded device net_bonding_testpmd_[\d] on \(= port ", > > + "Created new bonded device eth_bond_testpmd_[\d] on \(por= t "] > > + 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_por= t) > > + self.verify("Bonding mode: %d" % mode in out, > > + "Bonding mode display error when create bonded= device") > > + self.verify("Slaves: []" in out, > > + "Slaves display error when create bonded devic= e") > > + self.verify("Active Slaves: []" in out, > > + "Active Slaves display error when create bonde= d device") > > + self.verify("Primary: []" not in out, > > + "Primary display error when create bonded devi= ce") > > + 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= _str)) > > + 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= fail" > > + self.verify(str(slave_id) not in slaves, err) > > + > > + def remove_slaves(self, bond_port, invert_verify=3DFalse, *slave_p= ort): > > + """ > > + 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 devic= e" > > + self.logger.error(msg) > > + for slave_id in slave_port: > > + cmd =3D "remove bonding slave %d %d" % (int(slave_id), bon= d_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= =3DFalse): > > + """ > > + 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= success" > > + 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, = policy) > > + self.d_console(cmd) > > + new_policy =3D self.get_bonding_info(bond_port, 'balance_polic= y') > > + policy =3D "BALANCE_XMIT_POLICY_LAYER" + policy.lstrip('l') > > + self.verify(new_policy =3D=3D policy, "Set bonding balance pol= icy > > + failed") > > + > > + @property > > + def is_perf(self): > > + return self.parent._enable_perf > > -- > > 1.9.3