* [dts] [PATCH V1][pmd bonding]: common methods used by bonding suites
@ 2019-02-28 5:50 yufengmx
2019-02-28 5:50 ` [dts] [PATCH V1]pmd_bonding: " yufengmx
0 siblings, 1 reply; 5+ messages in thread
From: yufengmx @ 2019-02-28 5:50 UTC (permalink / raw)
To: dts; +Cc: yufengmx
a module that common methods are ran by pmd_bonded_8023ad/pmd_stacked_bonded suites
yufengmx (1):
pmd_bonding: common methods used by bonding suites
tests/bonding.py | 831 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 831 insertions(+)
create mode 100644 tests/bonding.py
--
1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [dts] [PATCH V1]pmd_bonding: common methods used by bonding suites
2019-02-28 5:50 [dts] [PATCH V1][pmd bonding]: common methods used by bonding suites yufengmx
@ 2019-02-28 5:50 ` yufengmx
2019-02-28 6:03 ` Mo, YufengX
2019-02-28 11:00 ` Tu, Lijuan
0 siblings, 2 replies; 5+ messages in thread
From: yufengmx @ 2019-02-28 5:50 UTC (permalink / raw)
To: dts; +Cc: yufengmx
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 <yufengx.mo@intel.com>
---
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 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 = 0
+MODE_ACTIVE_BACKUP = 1
+MODE_XOR_BALANCE = 2
+MODE_BROADCAST = 3
+MODE_LACP = 4
+MODE_TLB_BALANCE = 5
+MODE_ALB_BALANCE = 6
+
+# define packet size
+FRAME_SIZE_64 = 64
+FRAME_SIZE_128 = 128
+FRAME_SIZE_256 = 256
+FRAME_SIZE_512 = 512
+FRAME_SIZE_1024 = 1024
+FRAME_SIZE_1518 = 1518
+
+class PmdBonding(object):
+ ''' common methods for testpmd bonding '''
+
+ def __init__(self, **kwargs):
+ # set parent instance
+ self.parent = kwargs.get('parent')
+ # set target source code directory
+ self.target_source = self.parent.dut.base_dir
+ # set logger
+ self.logger = self.parent.logger
+ self.verify = self.parent.verify
+ # select packet generator
+ self.pktgen_name = 'ixia' if self.is_perf else 'scapy'
+ # traffic default config
+ self.default_pkt_size = kwargs.get('pkt_size') or FRAME_SIZE_64
+ self.default_src_mac = kwargs.get('src_mac')
+ self.default_src_ip = kwargs.get('src_ip')
+ self.default_src_port = kwargs.get('src_port')
+ self.default_dst_ip = kwargs.get('dst_ip')
+ self.default_dst_port = kwargs.get('dst_port')
+ self.default_pkt_name = kwargs.get('pkt_name')
+ # testpmd
+ self.testpmd = PmdOutput(self.parent.dut)
+ self.testpmd_status = '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 = '0x'
+ for mac_part in mac_str.split(':'):
+ mac_hex += 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 = hex(mac_int)[2:]
+ b = []
+ [b.append(temp[n:n+2]) for n in range(len(temp)) if n % 2 == 0]
+ new_mac = ":".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 = 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 = socket.inet_ntoa(struct.pack('I', socket.htonl(ip_int)))
+ return ip_str
+
+ def increase_ip(self, ip, step=1):
+ ''' ip: string format '''
+ _ip_int = self.ip_str_to_int(ip)
+ new_ip = self.ip_int_to_str(_ip_int + step)
+ return new_ip
+
+ def increase_mac(self, mac, step=1):
+ ''' mac: string format '''
+ _mac_int = self.mac_str_to_int(mac)
+ new_mac = self.mac_int_to_str(_mac_int+step)
+ return new_mac
+
+ def increase_port(self, port, step=1):
+ ''' port: int format '''
+ new_port = port + step
+ return new_port
+
+ def increase_mac_ip_port(self, step=1):
+ # get source port setting
+ mac, ip, port = (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 = self.default_pkt_size
+ headers_size = sum(map(lambda x: HEADER_SIZE[x],
+ ['eth', 'ip', pkt_type]))
+ pktlen = 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 = self.default_pkt_name
+ destport = self.default_dst_port
+ destip = self.default_dst_ip
+ dst_mac = self.get_port_info(dut_port_id, 'mac')
+ # packet size
+ pktlen = self.get_pkt_len(pkt_name)
+ # set stream configuration
+ srcmac, srcip, srcport = self.increase_mac_ip_port(0)
+ pkt_config = {
+ 'type': pkt_name.upper(),
+ 'pkt_layers': {
+ # Ether(dst=nutmac, src=srcmac)
+ 'ether': {'src': srcmac, 'dst': dst_mac},
+ # IP(dst=destip, src=srcip, len=%s)
+ 'ipv4': {'src': srcip, 'dst': destip},
+ # pkt_name(sport=srcport, dport=destport)
+ pkt_name: {'src': srcport, 'dst': destport},
+ # Raw(load='\x50'*%s)
+ 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}}
+ # create packet
+ streams = []
+ # keep a copy of pcap for debug
+ savePath = os.sep.join([self.target_source,
+ "pkt_{0}.pcap".format(pkt_name)])
+ pkt_type = pkt_config.get('type')
+ pkt_layers = pkt_config.get('pkt_layers')
+ pkt = Packet(pkt_type=pkt_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 = []
+ # get dst port mac address
+ pkt_name = self.default_pkt_name
+ destport = self.default_dst_port
+ destip = self.default_dst_ip
+ dst_mac = self.get_port_info(bond_port, 'mac')
+ # packet size
+ pktlen = self.get_pkt_len(pkt_type)
+ # set stream configuration
+ for packet_id in range(len(slaves['active'])):
+ srcmac, srcip, srcport = self.increase_mac_ip_port(packet_id)
+ pkt_configs.append({
+ 'type': pkt_name.upper(),
+ 'pkt_layers': {
+ # Ether(dst=nutmac, src=srcmac)
+ 'ether': {'src': srcmac, 'dst': dst_mac},
+ # IP(dst=destip, src=srcip, len=%s)
+ 'ipv4': {'src': srcip, 'dst': destip},
+ # pkt_name(sport=srcport, dport=destport)
+ pkt_name: {'src': srcport, 'dst': destport},
+ # Raw(load='\x50'*%s)
+ 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}})
+ # create packet
+ streams = []
+ for values in pkt_configs:
+ # keep a copy of pcap for debug
+ savePath = os.sep.join([self.target_source,
+ "pkt_{0}.pcap".format(stm_name)])
+ pkt_type = values.get('type')
+ pkt_layers = values.get('pkt_layers')
+ pkt = Packet(pkt_type=pkt_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 = kwargs.get('port topo')[0]
+ # set interface ready to send packet
+ cmd = "ifconfig {0} up".format(tx_iface)
+ self.parent.tester.send_expect(cmd, '# ', 30)
+ send_pkts = kwargs.get('stream')
+ # stream config
+ stream_configs = kwargs.get('traffic configs')
+ count = stream_configs.get('count')
+ interval = stream_configs.get('interval', 0.01)
+ # run traffic
+ sendp(send_pkts, iface=tx_iface, inter=interval, verbose=False,
+ count=count)
+
+ def send_packets_by_ixia(self, **kwargs):
+ tester_port = kwargs.get('tx_intf')
+ count = kwargs.get('count', 1)
+ traffic_type = kwargs.get('traffic_type', 'normal')
+ traffic_time = kwargs.get('traffic_time', 0)
+ rate_percent = kwargs.get('rate_percent', float(100))
+ #---------------------------------------------------------------
+ send_pkts = []
+ self.tgen_input = []
+ tgen_input = self.tgen_input
+ # generate packet contain multi stream
+ for pkt in self.packet_types.values():
+ send_pkts.append(pkt.pktgen.pkt)
+ ixia_pkt = os.sep.join([self.target_source, 'bonding_ixia.pcap'])
+ wrpcap(ixia_pkt, send_pkts)
+ #----------------------------------------------------------------
+ # set packet for send
+ # pause frame basic configuration
+ pause_time = 65535
+ pause_rate = 0.50
+ # run ixia testing
+ frame_size = self.default_pkt_size
+ # calculate number of packets
+ expect_pps = self.parent.wirespeed(self.parent.nic, frame_size, 1) * \
+ 1000000.0
+ # get line rate
+ linerate = expect_pps * (frame_size + 20) * 8
+ # calculate default sleep time for one pause frame
+ sleep = (1 / linerate) * pause_time * 512
+ # calculate packets dropped in sleep time
+ self.n_pkts = int((sleep / (1 / expect_pps)) * (1 / pause_rate))
+ #----------------------------------------------------------------
+ tester_port = 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_input,
+ self.rate_percent)
+
+ def stop_ixia(self, data_types='packets'):
+ tester_inst = self.parent.tester
+ # get ixia statistics
+ line_rate = tester_inst.get_port_line_rate()
+ rx_bps, rx_pps = \
+ tester_inst.stop_traffic_generator_throughput_loop(self.tgen_input)
+ output = tester_inst.traffic_get_port_stats(self.tgen_input)
+ self.cur_data['ixia statistics'] = []
+ append = 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 = {
+ 'ixia': self.send_packets_by_ixia,
+ 'scapy': self.send_packets_by_scapy,}
+ pkt_generator = 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 = self.get_pktgen(self.pktgen_name)
+ result = 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='testpmd'):
+ cmd = "ps aux | grep -i %s | grep -v grep | awk {'print $2'}"%(
+ process_name)
+ out = self.parent.dut.alt_session.send_expect(cmd, "# ", 10)
+ status = True if out != "" else False
+ return status
+
+ def check_process_exist(self, process_name='testpmd'):
+ status = self.check_process_status(process_name)
+ if not status:
+ msg = "{0} process exceptional quit".format(process_name)
+ out = 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) == 0:
+ return
+ # check if cmds is string
+ if isinstance(cmds, str):
+ timeout = 10
+ cmds = [[cmds, '', timeout]]
+ # check if cmds is only one command
+ if not isinstance(cmds[0], list):
+ cmds = [cmds]
+ outputs = [] if len(cmds) > 1 else ''
+ for item in cmds:
+ expected_items = item[1]
+ if expected_items and isinstance(expected_items, (list, tuple)):
+ check_output = True
+ expected_str = expected_items[0] or 'testpmd> '
+ else:
+ check_output = False
+ expected_str = expected_items or 'testpmd> '
+ timeout = int(item[2]) if len(item) == 3 else 5
+ #----------------------------------------------------------------
+ # run command on session
+ try:
+ console = self.testpmd.execute_cmd
+ msg_pipe = self.testpmd.get_output
+ output = console(item[0], expected_str, timeout)
+ output = 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 = 'close'
+ msg = "execute '{0}' timeout".format(item[0])
+ output = out = self.parent.dut.session.session.get_output_all()
+ self.logger.error(output)
+ raise Exception(msg)
+
+ if len(cmds) > 1:
+ outputs.append(output)
+ else:
+ outputs = output
+ if check_output and len(expected_items) >= 2:
+ self.logger.info(output)
+ expected_output = expected_items[1]
+ check_type = True if len(expected_items) == 2 \
+ else expected_items[2]
+ if check_type and expected_output in output:
+ msg = "expected '{0}' is in output".format(expected_output)
+ self.logger.info(msg)
+ elif not check_type and expected_output not in output:
+ fmt = "unexpected '{0}' is not in output"
+ msg = fmt.format(expected_output)
+ self.logger.info(msg)
+ else:
+ status = "isn't in" if check_type else "is in"
+ msg = "[{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='', eal_param=''):
+ try:
+ self.testpmd.start_testpmd( core_mask,
+ param=' '.join(options),
+ eal_param=eal_param)
+ except TimeoutException:
+ # check if testpmd quit
+ try:
+ self.check_process_exist()
+ except Exception as e:
+ self.testpmd_status = 'close'
+ msg = "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 = []
+ time.sleep(1)
+
+ def start_testpmd(self, eal_option=''):
+ if self.testpmd_status == 'running':
+ return
+ # boot up testpmd
+ hw_mask = 'all'
+ options = ''
+ self.preset_testpmd_cmds = ['port stop all', '', 15]
+ self.preset_testpmd(hw_mask, options, eal_param=eal_option)
+ self.testpmd_status = 'running'
+
+ def stop_testpmd(self):
+ time.sleep(1)
+ testpmd_cmds =[['port stop all', '', 15],
+ ['show port stats all', ''],
+ ['stop', ''],]
+ output = self.d_console(testpmd_cmds)
+ time.sleep(1)
+ return output
+
+ def close_testpmd(self):
+ if self.testpmd_status == 'close':
+ return None
+ output = 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 = 'close'
+ return output
+
+ def start_ports(self, port='all'):
+ """
+ Start a port which the testpmd can see.
+ """
+ timeout = 12 if port=='all' else 5
+ cmds =[
+ ["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=['rx', 'tx']):
+ """
+ get one port statistics of testpmd
+ """
+ _portid = int(portid) if isinstance(portid, (str, unicode)) else portid
+ info = self.testpmd.get_pmd_stats(_portid)
+ _kwd = ["-packets", "-errors", "-bytes"]
+ stats = {}
+ if isinstance(flow, list):
+ for item in flow:
+ for item2 in _kwd:
+ name = item.upper() + item2
+ stats[name] = int(info[name])
+ elif isinstance(flow, (str, unicode)):
+ for item in _kwd:
+ name = flow.upper() + item
+ stats[name] = int(info[name])
+ else:
+ msg = '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 = {}
+ attrs = ['tx', 'rx']
+ for port_id in ports:
+ stats[port_id] = 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 = 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 = self.parent.tester.get_local_port(self.parent.dut_ports[port_id])
+ self.set_tester_port_status(intf, status)
+ time.sleep(5)
+ cur_status = self.get_port_info(port_id, 'link_status')
+ self.logger.info("port {0} is [{1}]".format(port_id, cur_status))
+ if cur_status != status:
+ self.logger.warning("expected status is [{0}]".format(status))
+
+ def set_dut_port_status(self, port_id, status):
+ opt = 'link-up' if status == 'up' else 'link-down'
+ # stop slave link by force
+ cmd = "set {0} port {1}".format(opt, port_id)
+ self.d_console(cmd)
+ time.sleep(5)
+ cur_status = self.get_port_info(port_id, 'link_status')
+ self.logger.info("port {0} is [{1}]".format(port_id, cur_status))
+ if cur_status != 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 = r"(?<=%s)%s" % (key_str, regx_str)
+ s = re.compile(pattern)
+ res = s.search(string)
+ if type(res).__name__ == 'NoneType':
+ msg = "{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 = r"(?<=%s)%s" % (key, regx_str)
+ s = re.compile(pattern)
+ res = s.search(string)
+ if type(res).__name__ == '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 <port num>'.
+ """
+ key_str, regx_str = args
+ out = self.d_console("show port info %d" % port_id)
+ find_value = 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 = {
+ '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 = 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 = args
+ find_value = 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 = args if isinstance(args[0], (list, tuple)) else [args]
+ for search_args in search_args:
+ try:
+ info = self.get_bonding_config(config_content, search_args)
+ break
+ except Exception as e:
+ self.logger.info(e)
+ else:
+ info = None
+
+ return info
+
+ def get_bonding_info(self, bond_port, info_types):
+ ''' Get the specified port information by its output message format '''
+ info_set = {
+ '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 = self.d_console("show bonding config %d" % bond_port)
+ if isinstance(info_types, (list or tuple)):
+ query_values = []
+ for info_type in info_types:
+ if info_type in info_set.keys():
+ find_value = self.get_info_from_bond_config(
+ config_content, info_set[info_type])
+ if info_type in ['active_slaves', 'slaves']:
+ find_value = [value for value in find_value.split(' ')
+ if value]
+ else:
+ find_value = None
+ query_values.append(find_value)
+ return query_values
+ else:
+ info_type = info_types
+ if info_type in info_set.keys():
+ find_value = self.get_info_from_bond_config(
+ config_content, info_set[info_type])
+ if info_type in ['active_slaves', 'slaves']:
+ find_value = [value for value in find_value.split(' ')
+ if value]
+ return find_value
+ else:
+ return None
+
+ def get_active_slaves(self, bond_port):
+ primary_port = int(self.get_bonding_info(bond_port, 'primary'))
+ active_slaves = 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=0, socket=0, verify_detail=False):
+ """
+ Create a bonding device with the parameters you specified.
+ """
+ cmd = "create bonded device %d %d" % (mode, socket)
+ out = self.d_console(cmd)
+ err_fmt = "Create bonded device on mode [%d] socket [%d] failed"
+ self.verify("Created new bonded device" in out, err_fmt% (mode, socket))
+ fmts = [
+ "Created new bonded device net_bond_testpmd_[\d] on \(port ",
+ "Created new bonded device net_bonding_testpmd_[\d] on \(port ",
+ "Created new bonded device eth_bond_testpmd_[\d] on \(port "]
+ bond_port = self.get_value_from_str(fmts, "\d+", out)
+ bond_port = int(bond_port)
+
+ if verify_detail:
+ out = self.d_console("show bonding config %d" % bond_port)
+ 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 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 = 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=False, expected_str='',
+ *slave_ports):
+ """
+ Add ports into the bonding device as slaves.
+ """
+ if len(slave_ports) <= 0:
+ utils.RED("No port exist when add slave to bonded device")
+ for slave_id in slave_ports:
+ cmd = "add bonding slave %d %d" % (slave_id, bond_port)
+ out = self.d_console(cmd)
+ if expected_str:
+ self.verify(expected_str in out,
+ "message <{0}> is missing".format(expected_str))
+ slaves = 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 = "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=False, *slave_port):
+ """
+ Remove the specified slave port from the bonding device.
+ """
+ if len(slave_port) <= 0:
+ msg = "No port exist when remove slave from bonded device"
+ self.logger.error(msg)
+ for slave_id in slave_port:
+ cmd = "remove bonding slave %d %d" % (int(slave_id), bond_port)
+ self.d_console(cmd)
+ slaves = 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 = (
+ "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 = self.get_bonding_info(bond_port, 'slaves')
+ if not all_slaves:
+ return
+ all_slaves = all_slaves.split()
+ if len(all_slaves) == 0:
+ return
+ self.remove_slaves(bond_port, False, *all_slaves)
+
+ def set_primary_slave(self, bond_port, slave_port, invert_verify=False):
+ """
+ Set the primary slave for the bonding device.
+ """
+ cmd = "set bonding primary %d %d" % (slave_port, bond_port)
+ self.d_console(cmd)
+ out = 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 = "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 = "set bonding mode %d %d" % (mode, bond_port)
+ self.d_console(cmd)
+ mode_value = 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 = "set bonding mac_addr %s %s" % (bond_port, mac)
+ self.d_console(cmd)
+ new_mac = self.get_port_mac(bond_port)
+ self.verify(new_mac == mac, "Set bonding mac failed")
+
+ def get_port_mac(self, bond_port, query_type):
+ bond_port_mac = 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 = "set bonding balance_xmit_policy %d %s" % (bond_port, policy)
+ self.d_console(cmd)
+ new_policy = self.get_bonding_info(bond_port, 'balance_policy')
+ policy = "BALANCE_XMIT_POLICY_LAYER" + policy.lstrip('l')
+ self.verify(new_policy == policy, "Set bonding balance policy failed")
+
+ @property
+ def is_perf(self):
+ return self.parent._enable_perf
--
1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [dts] [PATCH V1]pmd_bonding: common methods used by bonding suites
2019-02-28 5:50 ` [dts] [PATCH V1]pmd_bonding: " yufengmx
@ 2019-02-28 6:03 ` Mo, YufengX
2019-02-28 8:40 ` Chen, Zhaoyan
2019-02-28 11:00 ` Tu, Lijuan
1 sibling, 1 reply; 5+ messages in thread
From: Mo, YufengX @ 2019-02-28 6:03 UTC (permalink / raw)
To: dts; +Cc: Mo, YufengX
Tested-by: Mo, YufengX <yufengx.mo@intel.com>
> -----Original Message-----
> From: Mo, YufengX
> Sent: Thursday, February 28, 2019 1:50 PM
> To: dts@dpdk.org
> Cc: Mo, YufengX <yufengx.mo@intel.com>
> 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 <yufengx.mo@intel.com>
> ---
> 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 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 = 0
> +MODE_ACTIVE_BACKUP = 1
> +MODE_XOR_BALANCE = 2
> +MODE_BROADCAST = 3
> +MODE_LACP = 4
> +MODE_TLB_BALANCE = 5
> +MODE_ALB_BALANCE = 6
> +
> +# define packet size
> +FRAME_SIZE_64 = 64
> +FRAME_SIZE_128 = 128
> +FRAME_SIZE_256 = 256
> +FRAME_SIZE_512 = 512
> +FRAME_SIZE_1024 = 1024
> +FRAME_SIZE_1518 = 1518
> +
> +class PmdBonding(object):
> + ''' common methods for testpmd bonding '''
> +
> + def __init__(self, **kwargs):
> + # set parent instance
> + self.parent = kwargs.get('parent')
> + # set target source code directory
> + self.target_source = self.parent.dut.base_dir
> + # set logger
> + self.logger = self.parent.logger
> + self.verify = self.parent.verify
> + # select packet generator
> + self.pktgen_name = 'ixia' if self.is_perf else 'scapy'
> + # traffic default config
> + self.default_pkt_size = kwargs.get('pkt_size') or FRAME_SIZE_64
> + self.default_src_mac = kwargs.get('src_mac')
> + self.default_src_ip = kwargs.get('src_ip')
> + self.default_src_port = kwargs.get('src_port')
> + self.default_dst_ip = kwargs.get('dst_ip')
> + self.default_dst_port = kwargs.get('dst_port')
> + self.default_pkt_name = kwargs.get('pkt_name')
> + # testpmd
> + self.testpmd = PmdOutput(self.parent.dut)
> + self.testpmd_status = '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 = '0x'
> + for mac_part in mac_str.split(':'):
> + mac_hex += 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 = hex(mac_int)[2:]
> + b = []
> + [b.append(temp[n:n+2]) for n in range(len(temp)) if n % 2 == 0]
> + new_mac = ":".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 = 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 = socket.inet_ntoa(struct.pack('I', socket.htonl(ip_int)))
> + return ip_str
> +
> + def increase_ip(self, ip, step=1):
> + ''' ip: string format '''
> + _ip_int = self.ip_str_to_int(ip)
> + new_ip = self.ip_int_to_str(_ip_int + step)
> + return new_ip
> +
> + def increase_mac(self, mac, step=1):
> + ''' mac: string format '''
> + _mac_int = self.mac_str_to_int(mac)
> + new_mac = self.mac_int_to_str(_mac_int+step)
> + return new_mac
> +
> + def increase_port(self, port, step=1):
> + ''' port: int format '''
> + new_port = port + step
> + return new_port
> +
> + def increase_mac_ip_port(self, step=1):
> + # get source port setting
> + mac, ip, port = (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 = self.default_pkt_size
> + headers_size = sum(map(lambda x: HEADER_SIZE[x],
> + ['eth', 'ip', pkt_type]))
> + pktlen = 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 = self.default_pkt_name
> + destport = self.default_dst_port
> + destip = self.default_dst_ip
> + dst_mac = self.get_port_info(dut_port_id, 'mac')
> + # packet size
> + pktlen = self.get_pkt_len(pkt_name)
> + # set stream configuration
> + srcmac, srcip, srcport = self.increase_mac_ip_port(0)
> + pkt_config = {
> + 'type': pkt_name.upper(),
> + 'pkt_layers': {
> + # Ether(dst=nutmac, src=srcmac)
> + 'ether': {'src': srcmac, 'dst': dst_mac},
> + # IP(dst=destip, src=srcip, len=%s)
> + 'ipv4': {'src': srcip, 'dst': destip},
> + # pkt_name(sport=srcport, dport=destport)
> + pkt_name: {'src': srcport, 'dst': destport},
> + # Raw(load='\x50'*%s)
> + 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}}
> + # create packet
> + streams = []
> + # keep a copy of pcap for debug
> + savePath = os.sep.join([self.target_source,
> + "pkt_{0}.pcap".format(pkt_name)])
> + pkt_type = pkt_config.get('type')
> + pkt_layers = pkt_config.get('pkt_layers')
> + pkt = Packet(pkt_type=pkt_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 = []
> + # get dst port mac address
> + pkt_name = self.default_pkt_name
> + destport = self.default_dst_port
> + destip = self.default_dst_ip
> + dst_mac = self.get_port_info(bond_port, 'mac')
> + # packet size
> + pktlen = self.get_pkt_len(pkt_type)
> + # set stream configuration
> + for packet_id in range(len(slaves['active'])):
> + srcmac, srcip, srcport = self.increase_mac_ip_port(packet_id)
> + pkt_configs.append({
> + 'type': pkt_name.upper(),
> + 'pkt_layers': {
> + # Ether(dst=nutmac, src=srcmac)
> + 'ether': {'src': srcmac, 'dst': dst_mac},
> + # IP(dst=destip, src=srcip, len=%s)
> + 'ipv4': {'src': srcip, 'dst': destip},
> + # pkt_name(sport=srcport, dport=destport)
> + pkt_name: {'src': srcport, 'dst': destport},
> + # Raw(load='\x50'*%s)
> + 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}})
> + # create packet
> + streams = []
> + for values in pkt_configs:
> + # keep a copy of pcap for debug
> + savePath = os.sep.join([self.target_source,
> + "pkt_{0}.pcap".format(stm_name)])
> + pkt_type = values.get('type')
> + pkt_layers = values.get('pkt_layers')
> + pkt = Packet(pkt_type=pkt_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 = kwargs.get('port topo')[0]
> + # set interface ready to send packet
> + cmd = "ifconfig {0} up".format(tx_iface)
> + self.parent.tester.send_expect(cmd, '# ', 30)
> + send_pkts = kwargs.get('stream')
> + # stream config
> + stream_configs = kwargs.get('traffic configs')
> + count = stream_configs.get('count')
> + interval = stream_configs.get('interval', 0.01)
> + # run traffic
> + sendp(send_pkts, iface=tx_iface, inter=interval, verbose=False,
> + count=count)
> +
> + def send_packets_by_ixia(self, **kwargs):
> + tester_port = kwargs.get('tx_intf')
> + count = kwargs.get('count', 1)
> + traffic_type = kwargs.get('traffic_type', 'normal')
> + traffic_time = kwargs.get('traffic_time', 0)
> + rate_percent = kwargs.get('rate_percent', float(100))
> + #---------------------------------------------------------------
> + send_pkts = []
> + self.tgen_input = []
> + tgen_input = self.tgen_input
> + # generate packet contain multi stream
> + for pkt in self.packet_types.values():
> + send_pkts.append(pkt.pktgen.pkt)
> + ixia_pkt = os.sep.join([self.target_source, 'bonding_ixia.pcap'])
> + wrpcap(ixia_pkt, send_pkts)
> + #----------------------------------------------------------------
> + # set packet for send
> + # pause frame basic configuration
> + pause_time = 65535
> + pause_rate = 0.50
> + # run ixia testing
> + frame_size = self.default_pkt_size
> + # calculate number of packets
> + expect_pps = self.parent.wirespeed(self.parent.nic, frame_size, 1) * \
> + 1000000.0
> + # get line rate
> + linerate = expect_pps * (frame_size + 20) * 8
> + # calculate default sleep time for one pause frame
> + sleep = (1 / linerate) * pause_time * 512
> + # calculate packets dropped in sleep time
> + self.n_pkts = int((sleep / (1 / expect_pps)) * (1 / pause_rate))
> + #----------------------------------------------------------------
> + tester_port = 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_input,
> + self.rate_percent)
> +
> + def stop_ixia(self, data_types='packets'):
> + tester_inst = self.parent.tester
> + # get ixia statistics
> + line_rate = tester_inst.get_port_line_rate()
> + rx_bps, rx_pps = \
> + tester_inst.stop_traffic_generator_throughput_loop(self.tgen_input)
> + output = tester_inst.traffic_get_port_stats(self.tgen_input)
> + self.cur_data['ixia statistics'] = []
> + append = 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 = {
> + 'ixia': self.send_packets_by_ixia,
> + 'scapy': self.send_packets_by_scapy,}
> + pkt_generator = 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 = self.get_pktgen(self.pktgen_name)
> + result = 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='testpmd'):
> + cmd = "ps aux | grep -i %s | grep -v grep | awk {'print $2'}"%(
> + process_name)
> + out = self.parent.dut.alt_session.send_expect(cmd, "# ", 10)
> + status = True if out != "" else False
> + return status
> +
> + def check_process_exist(self, process_name='testpmd'):
> + status = self.check_process_status(process_name)
> + if not status:
> + msg = "{0} process exceptional quit".format(process_name)
> + out = 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) == 0:
> + return
> + # check if cmds is string
> + if isinstance(cmds, str):
> + timeout = 10
> + cmds = [[cmds, '', timeout]]
> + # check if cmds is only one command
> + if not isinstance(cmds[0], list):
> + cmds = [cmds]
> + outputs = [] if len(cmds) > 1 else ''
> + for item in cmds:
> + expected_items = item[1]
> + if expected_items and isinstance(expected_items, (list, tuple)):
> + check_output = True
> + expected_str = expected_items[0] or 'testpmd> '
> + else:
> + check_output = False
> + expected_str = expected_items or 'testpmd> '
> + timeout = int(item[2]) if len(item) == 3 else 5
> + #----------------------------------------------------------------
> + # run command on session
> + try:
> + console = self.testpmd.execute_cmd
> + msg_pipe = self.testpmd.get_output
> + output = console(item[0], expected_str, timeout)
> + output = 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 = 'close'
> + msg = "execute '{0}' timeout".format(item[0])
> + output = out = self.parent.dut.session.session.get_output_all()
> + self.logger.error(output)
> + raise Exception(msg)
> +
> + if len(cmds) > 1:
> + outputs.append(output)
> + else:
> + outputs = output
> + if check_output and len(expected_items) >= 2:
> + self.logger.info(output)
> + expected_output = expected_items[1]
> + check_type = True if len(expected_items) == 2 \
> + else expected_items[2]
> + if check_type and expected_output in output:
> + msg = "expected '{0}' is in output".format(expected_output)
> + self.logger.info(msg)
> + elif not check_type and expected_output not in output:
> + fmt = "unexpected '{0}' is not in output"
> + msg = fmt.format(expected_output)
> + self.logger.info(msg)
> + else:
> + status = "isn't in" if check_type else "is in"
> + msg = "[{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='', eal_param=''):
> + try:
> + self.testpmd.start_testpmd( core_mask,
> + param=' '.join(options),
> + eal_param=eal_param)
> + except TimeoutException:
> + # check if testpmd quit
> + try:
> + self.check_process_exist()
> + except Exception as e:
> + self.testpmd_status = 'close'
> + msg = "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 = []
> + time.sleep(1)
> +
> + def start_testpmd(self, eal_option=''):
> + if self.testpmd_status == 'running':
> + return
> + # boot up testpmd
> + hw_mask = 'all'
> + options = ''
> + self.preset_testpmd_cmds = ['port stop all', '', 15]
> + self.preset_testpmd(hw_mask, options, eal_param=eal_option)
> + self.testpmd_status = 'running'
> +
> + def stop_testpmd(self):
> + time.sleep(1)
> + testpmd_cmds =[['port stop all', '', 15],
> + ['show port stats all', ''],
> + ['stop', ''],]
> + output = self.d_console(testpmd_cmds)
> + time.sleep(1)
> + return output
> +
> + def close_testpmd(self):
> + if self.testpmd_status == 'close':
> + return None
> + output = 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 = 'close'
> + return output
> +
> + def start_ports(self, port='all'):
> + """
> + Start a port which the testpmd can see.
> + """
> + timeout = 12 if port=='all' else 5
> + cmds =[
> + ["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=['rx', 'tx']):
> + """
> + get one port statistics of testpmd
> + """
> + _portid = int(portid) if isinstance(portid, (str, unicode)) else portid
> + info = self.testpmd.get_pmd_stats(_portid)
> + _kwd = ["-packets", "-errors", "-bytes"]
> + stats = {}
> + if isinstance(flow, list):
> + for item in flow:
> + for item2 in _kwd:
> + name = item.upper() + item2
> + stats[name] = int(info[name])
> + elif isinstance(flow, (str, unicode)):
> + for item in _kwd:
> + name = flow.upper() + item
> + stats[name] = int(info[name])
> + else:
> + msg = '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 = {}
> + attrs = ['tx', 'rx']
> + for port_id in ports:
> + stats[port_id] = 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 = 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 = self.parent.tester.get_local_port(self.parent.dut_ports[port_id])
> + self.set_tester_port_status(intf, status)
> + time.sleep(5)
> + cur_status = self.get_port_info(port_id, 'link_status')
> + self.logger.info("port {0} is [{1}]".format(port_id, cur_status))
> + if cur_status != status:
> + self.logger.warning("expected status is [{0}]".format(status))
> +
> + def set_dut_port_status(self, port_id, status):
> + opt = 'link-up' if status == 'up' else 'link-down'
> + # stop slave link by force
> + cmd = "set {0} port {1}".format(opt, port_id)
> + self.d_console(cmd)
> + time.sleep(5)
> + cur_status = self.get_port_info(port_id, 'link_status')
> + self.logger.info("port {0} is [{1}]".format(port_id, cur_status))
> + if cur_status != 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 = r"(?<=%s)%s" % (key_str, regx_str)
> + s = re.compile(pattern)
> + res = s.search(string)
> + if type(res).__name__ == 'NoneType':
> + msg = "{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 = r"(?<=%s)%s" % (key, regx_str)
> + s = re.compile(pattern)
> + res = s.search(string)
> + if type(res).__name__ == '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 <port num>'.
> + """
> + key_str, regx_str = args
> + out = self.d_console("show port info %d" % port_id)
> + find_value = 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 = {
> + '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 = 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 = args
> + find_value = 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 = args if isinstance(args[0], (list, tuple)) else [args]
> + for search_args in search_args:
> + try:
> + info = self.get_bonding_config(config_content, search_args)
> + break
> + except Exception as e:
> + self.logger.info(e)
> + else:
> + info = None
> +
> + return info
> +
> + def get_bonding_info(self, bond_port, info_types):
> + ''' Get the specified port information by its output message format '''
> + info_set = {
> + '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 = self.d_console("show bonding config %d" % bond_port)
> + if isinstance(info_types, (list or tuple)):
> + query_values = []
> + for info_type in info_types:
> + if info_type in info_set.keys():
> + find_value = self.get_info_from_bond_config(
> + config_content, info_set[info_type])
> + if info_type in ['active_slaves', 'slaves']:
> + find_value = [value for value in find_value.split(' ')
> + if value]
> + else:
> + find_value = None
> + query_values.append(find_value)
> + return query_values
> + else:
> + info_type = info_types
> + if info_type in info_set.keys():
> + find_value = self.get_info_from_bond_config(
> + config_content, info_set[info_type])
> + if info_type in ['active_slaves', 'slaves']:
> + find_value = [value for value in find_value.split(' ')
> + if value]
> + return find_value
> + else:
> + return None
> +
> + def get_active_slaves(self, bond_port):
> + primary_port = int(self.get_bonding_info(bond_port, 'primary'))
> + active_slaves = 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=0, socket=0, verify_detail=False):
> + """
> + Create a bonding device with the parameters you specified.
> + """
> + cmd = "create bonded device %d %d" % (mode, socket)
> + out = self.d_console(cmd)
> + err_fmt = "Create bonded device on mode [%d] socket [%d] failed"
> + self.verify("Created new bonded device" in out, err_fmt% (mode, socket))
> + fmts = [
> + "Created new bonded device net_bond_testpmd_[\d] on \(port ",
> + "Created new bonded device net_bonding_testpmd_[\d] on \(port ",
> + "Created new bonded device eth_bond_testpmd_[\d] on \(port "]
> + bond_port = self.get_value_from_str(fmts, "\d+", out)
> + bond_port = int(bond_port)
> +
> + if verify_detail:
> + out = self.d_console("show bonding config %d" % bond_port)
> + 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 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 = 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=False, expected_str='',
> + *slave_ports):
> + """
> + Add ports into the bonding device as slaves.
> + """
> + if len(slave_ports) <= 0:
> + utils.RED("No port exist when add slave to bonded device")
> + for slave_id in slave_ports:
> + cmd = "add bonding slave %d %d" % (slave_id, bond_port)
> + out = self.d_console(cmd)
> + if expected_str:
> + self.verify(expected_str in out,
> + "message <{0}> is missing".format(expected_str))
> + slaves = 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 = "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=False, *slave_port):
> + """
> + Remove the specified slave port from the bonding device.
> + """
> + if len(slave_port) <= 0:
> + msg = "No port exist when remove slave from bonded device"
> + self.logger.error(msg)
> + for slave_id in slave_port:
> + cmd = "remove bonding slave %d %d" % (int(slave_id), bond_port)
> + self.d_console(cmd)
> + slaves = 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 = (
> + "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 = self.get_bonding_info(bond_port, 'slaves')
> + if not all_slaves:
> + return
> + all_slaves = all_slaves.split()
> + if len(all_slaves) == 0:
> + return
> + self.remove_slaves(bond_port, False, *all_slaves)
> +
> + def set_primary_slave(self, bond_port, slave_port, invert_verify=False):
> + """
> + Set the primary slave for the bonding device.
> + """
> + cmd = "set bonding primary %d %d" % (slave_port, bond_port)
> + self.d_console(cmd)
> + out = 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 = "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 = "set bonding mode %d %d" % (mode, bond_port)
> + self.d_console(cmd)
> + mode_value = 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 = "set bonding mac_addr %s %s" % (bond_port, mac)
> + self.d_console(cmd)
> + new_mac = self.get_port_mac(bond_port)
> + self.verify(new_mac == mac, "Set bonding mac failed")
> +
> + def get_port_mac(self, bond_port, query_type):
> + bond_port_mac = 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 = "set bonding balance_xmit_policy %d %s" % (bond_port, policy)
> + self.d_console(cmd)
> + new_policy = self.get_bonding_info(bond_port, 'balance_policy')
> + policy = "BALANCE_XMIT_POLICY_LAYER" + policy.lstrip('l')
> + self.verify(new_policy == policy, "Set bonding balance policy failed")
> +
> + @property
> + def is_perf(self):
> + return self.parent._enable_perf
> --
> 1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [dts] [PATCH V1]pmd_bonding: common methods used by bonding suites
2019-02-28 6:03 ` Mo, YufengX
@ 2019-02-28 8:40 ` Chen, Zhaoyan
0 siblings, 0 replies; 5+ messages in thread
From: Chen, Zhaoyan @ 2019-02-28 8:40 UTC (permalink / raw)
To: Mo, YufengX, dts; +Cc: Mo, YufengX, Chen, Zhaoyan
Acked-by: Chen, Zhaoyan <zhaoyan.chen@intel.com>
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 <yufengx.mo@intel.com>
> Subject: Re: [dts] [PATCH V1]pmd_bonding: common methods used by bonding
> suites
>
>
> Tested-by: Mo, YufengX <yufengx.mo@intel.com>
>
> > -----Original Message-----
> > From: Mo, YufengX
> > Sent: Thursday, February 28, 2019 1:50 PM
> > To: dts@dpdk.org
> > Cc: Mo, YufengX <yufengx.mo@intel.com>
> > 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 <yufengx.mo@intel.com>
> > ---
> > 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 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 = 0
> > +MODE_ACTIVE_BACKUP = 1
> > +MODE_XOR_BALANCE = 2
> > +MODE_BROADCAST = 3
> > +MODE_LACP = 4
> > +MODE_TLB_BALANCE = 5
> > +MODE_ALB_BALANCE = 6
> > +
> > +# define packet size
> > +FRAME_SIZE_64 = 64
> > +FRAME_SIZE_128 = 128
> > +FRAME_SIZE_256 = 256
> > +FRAME_SIZE_512 = 512
> > +FRAME_SIZE_1024 = 1024
> > +FRAME_SIZE_1518 = 1518
> > +
> > +class PmdBonding(object):
> > + ''' common methods for testpmd bonding '''
> > +
> > + def __init__(self, **kwargs):
> > + # set parent instance
> > + self.parent = kwargs.get('parent')
> > + # set target source code directory
> > + self.target_source = self.parent.dut.base_dir
> > + # set logger
> > + self.logger = self.parent.logger
> > + self.verify = self.parent.verify
> > + # select packet generator
> > + self.pktgen_name = 'ixia' if self.is_perf else 'scapy'
> > + # traffic default config
> > + self.default_pkt_size = kwargs.get('pkt_size') or FRAME_SIZE_64
> > + self.default_src_mac = kwargs.get('src_mac')
> > + self.default_src_ip = kwargs.get('src_ip')
> > + self.default_src_port = kwargs.get('src_port')
> > + self.default_dst_ip = kwargs.get('dst_ip')
> > + self.default_dst_port = kwargs.get('dst_port')
> > + self.default_pkt_name = kwargs.get('pkt_name')
> > + # testpmd
> > + self.testpmd = PmdOutput(self.parent.dut)
> > + self.testpmd_status = '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 = '0x'
> > + for mac_part in mac_str.split(':'):
> > + mac_hex += 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 = hex(mac_int)[2:]
> > + b = []
> > + [b.append(temp[n:n+2]) for n in range(len(temp)) if n % 2 == 0]
> > + new_mac = ":".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 = 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 = socket.inet_ntoa(struct.pack('I', socket.htonl(ip_int)))
> > + return ip_str
> > +
> > + def increase_ip(self, ip, step=1):
> > + ''' ip: string format '''
> > + _ip_int = self.ip_str_to_int(ip)
> > + new_ip = self.ip_int_to_str(_ip_int + step)
> > + return new_ip
> > +
> > + def increase_mac(self, mac, step=1):
> > + ''' mac: string format '''
> > + _mac_int = self.mac_str_to_int(mac)
> > + new_mac = self.mac_int_to_str(_mac_int+step)
> > + return new_mac
> > +
> > + def increase_port(self, port, step=1):
> > + ''' port: int format '''
> > + new_port = port + step
> > + return new_port
> > +
> > + def increase_mac_ip_port(self, step=1):
> > + # get source port setting
> > + mac, ip, port = (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 = self.default_pkt_size
> > + headers_size = sum(map(lambda x: HEADER_SIZE[x],
> > + ['eth', 'ip', pkt_type]))
> > + pktlen = 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 = self.default_pkt_name
> > + destport = self.default_dst_port
> > + destip = self.default_dst_ip
> > + dst_mac = self.get_port_info(dut_port_id, 'mac')
> > + # packet size
> > + pktlen = self.get_pkt_len(pkt_name)
> > + # set stream configuration
> > + srcmac, srcip, srcport = self.increase_mac_ip_port(0)
> > + pkt_config = {
> > + 'type': pkt_name.upper(),
> > + 'pkt_layers': {
> > + # Ether(dst=nutmac, src=srcmac)
> > + 'ether': {'src': srcmac, 'dst': dst_mac},
> > + # IP(dst=destip, src=srcip, len=%s)
> > + 'ipv4': {'src': srcip, 'dst': destip},
> > + # pkt_name(sport=srcport, dport=destport)
> > + pkt_name: {'src': srcport, 'dst': destport},
> > + # Raw(load='\x50'*%s)
> > + 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}}
> > + # create packet
> > + streams = []
> > + # keep a copy of pcap for debug
> > + savePath = os.sep.join([self.target_source,
> > + "pkt_{0}.pcap".format(pkt_name)])
> > + pkt_type = pkt_config.get('type')
> > + pkt_layers = pkt_config.get('pkt_layers')
> > + pkt = Packet(pkt_type=pkt_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 = []
> > + # get dst port mac address
> > + pkt_name = self.default_pkt_name
> > + destport = self.default_dst_port
> > + destip = self.default_dst_ip
> > + dst_mac = self.get_port_info(bond_port, 'mac')
> > + # packet size
> > + pktlen = self.get_pkt_len(pkt_type)
> > + # set stream configuration
> > + for packet_id in range(len(slaves['active'])):
> > + srcmac, srcip, srcport = self.increase_mac_ip_port(packet_id)
> > + pkt_configs.append({
> > + 'type': pkt_name.upper(),
> > + 'pkt_layers': {
> > + # Ether(dst=nutmac, src=srcmac)
> > + 'ether': {'src': srcmac, 'dst': dst_mac},
> > + # IP(dst=destip, src=srcip, len=%s)
> > + 'ipv4': {'src': srcip, 'dst': destip},
> > + # pkt_name(sport=srcport, dport=destport)
> > + pkt_name: {'src': srcport, 'dst': destport},
> > + # Raw(load='\x50'*%s)
> > + 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}})
> > + # create packet
> > + streams = []
> > + for values in pkt_configs:
> > + # keep a copy of pcap for debug
> > + savePath = os.sep.join([self.target_source,
> > + "pkt_{0}.pcap".format(stm_name)])
> > + pkt_type = values.get('type')
> > + pkt_layers = values.get('pkt_layers')
> > + pkt = Packet(pkt_type=pkt_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 = kwargs.get('port topo')[0]
> > + # set interface ready to send packet
> > + cmd = "ifconfig {0} up".format(tx_iface)
> > + self.parent.tester.send_expect(cmd, '# ', 30)
> > + send_pkts = kwargs.get('stream')
> > + # stream config
> > + stream_configs = kwargs.get('traffic configs')
> > + count = stream_configs.get('count')
> > + interval = stream_configs.get('interval', 0.01)
> > + # run traffic
> > + sendp(send_pkts, iface=tx_iface, inter=interval, verbose=False,
> > + count=count)
> > +
> > + def send_packets_by_ixia(self, **kwargs):
> > + tester_port = kwargs.get('tx_intf')
> > + count = kwargs.get('count', 1)
> > + traffic_type = kwargs.get('traffic_type', 'normal')
> > + traffic_time = kwargs.get('traffic_time', 0)
> > + rate_percent = kwargs.get('rate_percent', float(100))
> > + #---------------------------------------------------------------
> > + send_pkts = []
> > + self.tgen_input = []
> > + tgen_input = self.tgen_input
> > + # generate packet contain multi stream
> > + for pkt in self.packet_types.values():
> > + send_pkts.append(pkt.pktgen.pkt)
> > + ixia_pkt = os.sep.join([self.target_source, 'bonding_ixia.pcap'])
> > + wrpcap(ixia_pkt, send_pkts)
> > + #----------------------------------------------------------------
> > + # set packet for send
> > + # pause frame basic configuration
> > + pause_time = 65535
> > + pause_rate = 0.50
> > + # run ixia testing
> > + frame_size = self.default_pkt_size
> > + # calculate number of packets
> > + expect_pps = self.parent.wirespeed(self.parent.nic, frame_size, 1) * \
> > + 1000000.0
> > + # get line rate
> > + linerate = expect_pps * (frame_size + 20) * 8
> > + # calculate default sleep time for one pause frame
> > + sleep = (1 / linerate) * pause_time * 512
> > + # calculate packets dropped in sleep time
> > + self.n_pkts = int((sleep / (1 / expect_pps)) * (1 / pause_rate))
> > + #----------------------------------------------------------------
> > + tester_port = 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_input,
> > +
> > + self.rate_percent)
> > +
> > + def stop_ixia(self, data_types='packets'):
> > + tester_inst = self.parent.tester
> > + # get ixia statistics
> > + line_rate = tester_inst.get_port_line_rate()
> > + rx_bps, rx_pps = \
> > + tester_inst.stop_traffic_generator_throughput_loop(self.tgen_input)
> > + output = tester_inst.traffic_get_port_stats(self.tgen_input)
> > + self.cur_data['ixia statistics'] = []
> > + append = 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 = {
> > + 'ixia': self.send_packets_by_ixia,
> > + 'scapy': self.send_packets_by_scapy,}
> > + pkt_generator = 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 = self.get_pktgen(self.pktgen_name)
> > + result = 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='testpmd'):
> > + cmd = "ps aux | grep -i %s | grep -v grep | awk {'print $2'}"%(
> > + process_name)
> > + out = self.parent.dut.alt_session.send_expect(cmd, "# ", 10)
> > + status = True if out != "" else False
> > + return status
> > +
> > + def check_process_exist(self, process_name='testpmd'):
> > + status = self.check_process_status(process_name)
> > + if not status:
> > + msg = "{0} process exceptional quit".format(process_name)
> > + out = 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) == 0:
> > + return
> > + # check if cmds is string
> > + if isinstance(cmds, str):
> > + timeout = 10
> > + cmds = [[cmds, '', timeout]]
> > + # check if cmds is only one command
> > + if not isinstance(cmds[0], list):
> > + cmds = [cmds]
> > + outputs = [] if len(cmds) > 1 else ''
> > + for item in cmds:
> > + expected_items = item[1]
> > + if expected_items and isinstance(expected_items, (list, tuple)):
> > + check_output = True
> > + expected_str = expected_items[0] or 'testpmd> '
> > + else:
> > + check_output = False
> > + expected_str = expected_items or 'testpmd> '
> > + timeout = int(item[2]) if len(item) == 3 else 5
> > + #----------------------------------------------------------------
> > + # run command on session
> > + try:
> > + console = self.testpmd.execute_cmd
> > + msg_pipe = self.testpmd.get_output
> > + output = console(item[0], expected_str, timeout)
> > + output = 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 = 'close'
> > + msg = "execute '{0}' timeout".format(item[0])
> > + output = out = self.parent.dut.session.session.get_output_all()
> > + self.logger.error(output)
> > + raise Exception(msg)
> > +
> > + if len(cmds) > 1:
> > + outputs.append(output)
> > + else:
> > + outputs = output
> > + if check_output and len(expected_items) >= 2:
> > + self.logger.info(output)
> > + expected_output = expected_items[1]
> > + check_type = True if len(expected_items) == 2 \
> > + else expected_items[2]
> > + if check_type and expected_output in output:
> > + msg = "expected '{0}' is in output".format(expected_output)
> > + self.logger.info(msg)
> > + elif not check_type and expected_output not in output:
> > + fmt = "unexpected '{0}' is not in output"
> > + msg = fmt.format(expected_output)
> > + self.logger.info(msg)
> > + else:
> > + status = "isn't in" if check_type else "is in"
> > + msg = "[{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='', eal_param=''):
> > + try:
> > + self.testpmd.start_testpmd( core_mask,
> > + param=' '.join(options),
> > + eal_param=eal_param)
> > + except TimeoutException:
> > + # check if testpmd quit
> > + try:
> > + self.check_process_exist()
> > + except Exception as e:
> > + self.testpmd_status = 'close'
> > + msg = "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 = []
> > + time.sleep(1)
> > +
> > + def start_testpmd(self, eal_option=''):
> > + if self.testpmd_status == 'running':
> > + return
> > + # boot up testpmd
> > + hw_mask = 'all'
> > + options = ''
> > + self.preset_testpmd_cmds = ['port stop all', '', 15]
> > + self.preset_testpmd(hw_mask, options, eal_param=eal_option)
> > + self.testpmd_status = 'running'
> > +
> > + def stop_testpmd(self):
> > + time.sleep(1)
> > + testpmd_cmds =[['port stop all', '', 15],
> > + ['show port stats all', ''],
> > + ['stop', ''],]
> > + output = self.d_console(testpmd_cmds)
> > + time.sleep(1)
> > + return output
> > +
> > + def close_testpmd(self):
> > + if self.testpmd_status == 'close':
> > + return None
> > + output = 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 = 'close'
> > + return output
> > +
> > + def start_ports(self, port='all'):
> > + """
> > + Start a port which the testpmd can see.
> > + """
> > + timeout = 12 if port=='all' else 5
> > + cmds =[
> > + ["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=['rx', 'tx']):
> > + """
> > + get one port statistics of testpmd
> > + """
> > + _portid = int(portid) if isinstance(portid, (str, unicode)) else portid
> > + info = self.testpmd.get_pmd_stats(_portid)
> > + _kwd = ["-packets", "-errors", "-bytes"]
> > + stats = {}
> > + if isinstance(flow, list):
> > + for item in flow:
> > + for item2 in _kwd:
> > + name = item.upper() + item2
> > + stats[name] = int(info[name])
> > + elif isinstance(flow, (str, unicode)):
> > + for item in _kwd:
> > + name = flow.upper() + item
> > + stats[name] = int(info[name])
> > + else:
> > + msg = '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 = {}
> > + attrs = ['tx', 'rx']
> > + for port_id in ports:
> > + stats[port_id] = 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 = 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 = self.parent.tester.get_local_port(self.parent.dut_ports[port_id])
> > + self.set_tester_port_status(intf, status)
> > + time.sleep(5)
> > + cur_status = self.get_port_info(port_id, 'link_status')
> > + self.logger.info("port {0} is [{1}]".format(port_id, cur_status))
> > + if cur_status != status:
> > + self.logger.warning("expected status is
> > + [{0}]".format(status))
> > +
> > + def set_dut_port_status(self, port_id, status):
> > + opt = 'link-up' if status == 'up' else 'link-down'
> > + # stop slave link by force
> > + cmd = "set {0} port {1}".format(opt, port_id)
> > + self.d_console(cmd)
> > + time.sleep(5)
> > + cur_status = self.get_port_info(port_id, 'link_status')
> > + self.logger.info("port {0} is [{1}]".format(port_id, cur_status))
> > + if cur_status != 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 = r"(?<=%s)%s" % (key_str, regx_str)
> > + s = re.compile(pattern)
> > + res = s.search(string)
> > + if type(res).__name__ == 'NoneType':
> > + msg = "{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 = r"(?<=%s)%s" % (key, regx_str)
> > + s = re.compile(pattern)
> > + res = s.search(string)
> > + if type(res).__name__ == '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 <port num>'.
> > + """
> > + key_str, regx_str = args
> > + out = self.d_console("show port info %d" % port_id)
> > + find_value = 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 = {
> > + '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 = 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 = args
> > + find_value = 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 = args if isinstance(args[0], (list, tuple)) else [args]
> > + for search_args in search_args:
> > + try:
> > + info = self.get_bonding_config(config_content, search_args)
> > + break
> > + except Exception as e:
> > + self.logger.info(e)
> > + else:
> > + info = None
> > +
> > + return info
> > +
> > + def get_bonding_info(self, bond_port, info_types):
> > + ''' Get the specified port information by its output message format '''
> > + info_set = {
> > + '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 = self.d_console("show bonding config %d" % bond_port)
> > + if isinstance(info_types, (list or tuple)):
> > + query_values = []
> > + for info_type in info_types:
> > + if info_type in info_set.keys():
> > + find_value = self.get_info_from_bond_config(
> > + config_content, info_set[info_type])
> > + if info_type in ['active_slaves', 'slaves']:
> > + find_value = [value for value in find_value.split(' ')
> > + if value]
> > + else:
> > + find_value = None
> > + query_values.append(find_value)
> > + return query_values
> > + else:
> > + info_type = info_types
> > + if info_type in info_set.keys():
> > + find_value = self.get_info_from_bond_config(
> > + config_content, info_set[info_type])
> > + if info_type in ['active_slaves', 'slaves']:
> > + find_value = [value for value in find_value.split(' ')
> > + if value]
> > + return find_value
> > + else:
> > + return None
> > +
> > + def get_active_slaves(self, bond_port):
> > + primary_port = int(self.get_bonding_info(bond_port, 'primary'))
> > + active_slaves = 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=0, socket=0, verify_detail=False):
> > + """
> > + Create a bonding device with the parameters you specified.
> > + """
> > + cmd = "create bonded device %d %d" % (mode, socket)
> > + out = self.d_console(cmd)
> > + err_fmt = "Create bonded device on mode [%d] socket [%d] failed"
> > + self.verify("Created new bonded device" in out, err_fmt% (mode, socket))
> > + fmts = [
> > + "Created new bonded device net_bond_testpmd_[\d] on \(port ",
> > + "Created new bonded device net_bonding_testpmd_[\d] on \(port ",
> > + "Created new bonded device eth_bond_testpmd_[\d] on \(port "]
> > + bond_port = self.get_value_from_str(fmts, "\d+", out)
> > + bond_port = int(bond_port)
> > +
> > + if verify_detail:
> > + out = self.d_console("show bonding config %d" % bond_port)
> > + 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 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 = 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=False, expected_str='',
> > + *slave_ports):
> > + """
> > + Add ports into the bonding device as slaves.
> > + """
> > + if len(slave_ports) <= 0:
> > + utils.RED("No port exist when add slave to bonded device")
> > + for slave_id in slave_ports:
> > + cmd = "add bonding slave %d %d" % (slave_id, bond_port)
> > + out = self.d_console(cmd)
> > + if expected_str:
> > + self.verify(expected_str in out,
> > + "message <{0}> is missing".format(expected_str))
> > + slaves = 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 = "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=False, *slave_port):
> > + """
> > + Remove the specified slave port from the bonding device.
> > + """
> > + if len(slave_port) <= 0:
> > + msg = "No port exist when remove slave from bonded device"
> > + self.logger.error(msg)
> > + for slave_id in slave_port:
> > + cmd = "remove bonding slave %d %d" % (int(slave_id), bond_port)
> > + self.d_console(cmd)
> > + slaves = 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 = (
> > + "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 = self.get_bonding_info(bond_port, 'slaves')
> > + if not all_slaves:
> > + return
> > + all_slaves = all_slaves.split()
> > + if len(all_slaves) == 0:
> > + return
> > + self.remove_slaves(bond_port, False, *all_slaves)
> > +
> > + def set_primary_slave(self, bond_port, slave_port, invert_verify=False):
> > + """
> > + Set the primary slave for the bonding device.
> > + """
> > + cmd = "set bonding primary %d %d" % (slave_port, bond_port)
> > + self.d_console(cmd)
> > + out = 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 = "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 = "set bonding mode %d %d" % (mode, bond_port)
> > + self.d_console(cmd)
> > + mode_value = 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 = "set bonding mac_addr %s %s" % (bond_port, mac)
> > + self.d_console(cmd)
> > + new_mac = self.get_port_mac(bond_port)
> > + self.verify(new_mac == mac, "Set bonding mac failed")
> > +
> > + def get_port_mac(self, bond_port, query_type):
> > + bond_port_mac = 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 = "set bonding balance_xmit_policy %d %s" % (bond_port, policy)
> > + self.d_console(cmd)
> > + new_policy = self.get_bonding_info(bond_port, 'balance_policy')
> > + policy = "BALANCE_XMIT_POLICY_LAYER" + policy.lstrip('l')
> > + self.verify(new_policy == policy, "Set bonding balance policy
> > + failed")
> > +
> > + @property
> > + def is_perf(self):
> > + return self.parent._enable_perf
> > --
> > 1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [dts] [PATCH V1]pmd_bonding: common methods used by bonding suites
2019-02-28 5:50 ` [dts] [PATCH V1]pmd_bonding: " yufengmx
2019-02-28 6:03 ` Mo, YufengX
@ 2019-02-28 11:00 ` Tu, Lijuan
1 sibling, 0 replies; 5+ messages in thread
From: Tu, Lijuan @ 2019-02-28 11:00 UTC (permalink / raw)
To: Mo, YufengX, dts; +Cc: Mo, YufengX
.git/rebase-apply/patch:213: trailing whitespace.
:param slaves:
.git/rebase-apply/patch:273: trailing whitespace.
rate_percent = 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 <yufengx.mo@intel.com>
> 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 <yufengx.mo@intel.com>
> ---
> 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 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 = 0
> +MODE_ACTIVE_BACKUP = 1
> +MODE_XOR_BALANCE = 2
> +MODE_BROADCAST = 3
> +MODE_LACP = 4
> +MODE_TLB_BALANCE = 5
> +MODE_ALB_BALANCE = 6
> +
> +# define packet size
> +FRAME_SIZE_64 = 64
> +FRAME_SIZE_128 = 128
> +FRAME_SIZE_256 = 256
> +FRAME_SIZE_512 = 512
> +FRAME_SIZE_1024 = 1024
> +FRAME_SIZE_1518 = 1518
> +
> +class PmdBonding(object):
> + ''' common methods for testpmd bonding '''
> +
> + def __init__(self, **kwargs):
> + # set parent instance
> + self.parent = kwargs.get('parent')
> + # set target source code directory
> + self.target_source = self.parent.dut.base_dir
> + # set logger
> + self.logger = self.parent.logger
> + self.verify = self.parent.verify
> + # select packet generator
> + self.pktgen_name = 'ixia' if self.is_perf else 'scapy'
> + # traffic default config
> + self.default_pkt_size = kwargs.get('pkt_size') or FRAME_SIZE_64
> + self.default_src_mac = kwargs.get('src_mac')
> + self.default_src_ip = kwargs.get('src_ip')
> + self.default_src_port = kwargs.get('src_port')
> + self.default_dst_ip = kwargs.get('dst_ip')
> + self.default_dst_port = kwargs.get('dst_port')
> + self.default_pkt_name = kwargs.get('pkt_name')
> + # testpmd
> + self.testpmd = PmdOutput(self.parent.dut)
> + self.testpmd_status = '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 = '0x'
> + for mac_part in mac_str.split(':'):
> + mac_hex += 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 = hex(mac_int)[2:]
> + b = []
> + [b.append(temp[n:n+2]) for n in range(len(temp)) if n % 2 == 0]
> + new_mac = ":".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 = 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 = socket.inet_ntoa(struct.pack('I', socket.htonl(ip_int)))
> + return ip_str
> +
> + def increase_ip(self, ip, step=1):
> + ''' ip: string format '''
> + _ip_int = self.ip_str_to_int(ip)
> + new_ip = self.ip_int_to_str(_ip_int + step)
> + return new_ip
> +
> + def increase_mac(self, mac, step=1):
> + ''' mac: string format '''
> + _mac_int = self.mac_str_to_int(mac)
> + new_mac = self.mac_int_to_str(_mac_int+step)
> + return new_mac
> +
> + def increase_port(self, port, step=1):
> + ''' port: int format '''
> + new_port = port + step
> + return new_port
> +
> + def increase_mac_ip_port(self, step=1):
> + # get source port setting
> + mac, ip, port = (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 = self.default_pkt_size
> + headers_size = sum(map(lambda x: HEADER_SIZE[x],
> + ['eth', 'ip', pkt_type]))
> + pktlen = 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 = self.default_pkt_name
> + destport = self.default_dst_port
> + destip = self.default_dst_ip
> + dst_mac = self.get_port_info(dut_port_id, 'mac')
> + # packet size
> + pktlen = self.get_pkt_len(pkt_name)
> + # set stream configuration
> + srcmac, srcip, srcport = self.increase_mac_ip_port(0)
> + pkt_config = {
> + 'type': pkt_name.upper(),
> + 'pkt_layers': {
> + # Ether(dst=nutmac, src=srcmac)
> + 'ether': {'src': srcmac, 'dst': dst_mac},
> + # IP(dst=destip, src=srcip, len=%s)
> + 'ipv4': {'src': srcip, 'dst': destip},
> + # pkt_name(sport=srcport, dport=destport)
> + pkt_name: {'src': srcport, 'dst': destport},
> + # Raw(load='\x50'*%s)
> + 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}}
> + # create packet
> + streams = []
> + # keep a copy of pcap for debug
> + savePath = os.sep.join([self.target_source,
> + "pkt_{0}.pcap".format(pkt_name)])
> + pkt_type = pkt_config.get('type')
> + pkt_layers = pkt_config.get('pkt_layers')
> + pkt = Packet(pkt_type=pkt_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 = []
> + # get dst port mac address
> + pkt_name = self.default_pkt_name
> + destport = self.default_dst_port
> + destip = self.default_dst_ip
> + dst_mac = self.get_port_info(bond_port, 'mac')
> + # packet size
> + pktlen = self.get_pkt_len(pkt_type)
> + # set stream configuration
> + for packet_id in range(len(slaves['active'])):
> + srcmac, srcip, srcport = self.increase_mac_ip_port(packet_id)
> + pkt_configs.append({
> + 'type': pkt_name.upper(),
> + 'pkt_layers': {
> + # Ether(dst=nutmac, src=srcmac)
> + 'ether': {'src': srcmac, 'dst': dst_mac},
> + # IP(dst=destip, src=srcip, len=%s)
> + 'ipv4': {'src': srcip, 'dst': destip},
> + # pkt_name(sport=srcport, dport=destport)
> + pkt_name: {'src': srcport, 'dst': destport},
> + # Raw(load='\x50'*%s)
> + 'raw': {'payload': ['58'] * self.get_pkt_len(pkt_name)}}})
> + # create packet
> + streams = []
> + for values in pkt_configs:
> + # keep a copy of pcap for debug
> + savePath = os.sep.join([self.target_source,
> + "pkt_{0}.pcap".format(stm_name)])
> + pkt_type = values.get('type')
> + pkt_layers = values.get('pkt_layers')
> + pkt = Packet(pkt_type=pkt_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 = kwargs.get('port topo')[0]
> + # set interface ready to send packet
> + cmd = "ifconfig {0} up".format(tx_iface)
> + self.parent.tester.send_expect(cmd, '# ', 30)
> + send_pkts = kwargs.get('stream')
> + # stream config
> + stream_configs = kwargs.get('traffic configs')
> + count = stream_configs.get('count')
> + interval = stream_configs.get('interval', 0.01)
> + # run traffic
> + sendp(send_pkts, iface=tx_iface, inter=interval, verbose=False,
> + count=count)
> +
> + def send_packets_by_ixia(self, **kwargs):
> + tester_port = kwargs.get('tx_intf')
> + count = kwargs.get('count', 1)
> + traffic_type = kwargs.get('traffic_type', 'normal')
> + traffic_time = kwargs.get('traffic_time', 0)
> + rate_percent = kwargs.get('rate_percent', float(100))
> + #---------------------------------------------------------------
> + send_pkts = []
> + self.tgen_input = []
> + tgen_input = self.tgen_input
> + # generate packet contain multi stream
> + for pkt in self.packet_types.values():
> + send_pkts.append(pkt.pktgen.pkt)
> + ixia_pkt = os.sep.join([self.target_source, 'bonding_ixia.pcap'])
> + wrpcap(ixia_pkt, send_pkts)
> + #----------------------------------------------------------------
> + # set packet for send
> + # pause frame basic configuration
> + pause_time = 65535
> + pause_rate = 0.50
> + # run ixia testing
> + frame_size = self.default_pkt_size
> + # calculate number of packets
> + expect_pps = self.parent.wirespeed(self.parent.nic, frame_size, 1) * \
> + 1000000.0
> + # get line rate
> + linerate = expect_pps * (frame_size + 20) * 8
> + # calculate default sleep time for one pause frame
> + sleep = (1 / linerate) * pause_time * 512
> + # calculate packets dropped in sleep time
> + self.n_pkts = int((sleep / (1 / expect_pps)) * (1 / pause_rate))
> + #----------------------------------------------------------------
> + tester_port = 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_input,
> +
> + self.rate_percent)
> +
> + def stop_ixia(self, data_types='packets'):
> + tester_inst = self.parent.tester
> + # get ixia statistics
> + line_rate = tester_inst.get_port_line_rate()
> + rx_bps, rx_pps = \
> + tester_inst.stop_traffic_generator_throughput_loop(self.tgen_input)
> + output = tester_inst.traffic_get_port_stats(self.tgen_input)
> + self.cur_data['ixia statistics'] = []
> + append = 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 = {
> + 'ixia': self.send_packets_by_ixia,
> + 'scapy': self.send_packets_by_scapy,}
> + pkt_generator = 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 = self.get_pktgen(self.pktgen_name)
> + result = 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='testpmd'):
> + cmd = "ps aux | grep -i %s | grep -v grep | awk {'print $2'}"%(
> + process_name)
> + out = self.parent.dut.alt_session.send_expect(cmd, "# ", 10)
> + status = True if out != "" else False
> + return status
> +
> + def check_process_exist(self, process_name='testpmd'):
> + status = self.check_process_status(process_name)
> + if not status:
> + msg = "{0} process exceptional quit".format(process_name)
> + out = 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) == 0:
> + return
> + # check if cmds is string
> + if isinstance(cmds, str):
> + timeout = 10
> + cmds = [[cmds, '', timeout]]
> + # check if cmds is only one command
> + if not isinstance(cmds[0], list):
> + cmds = [cmds]
> + outputs = [] if len(cmds) > 1 else ''
> + for item in cmds:
> + expected_items = item[1]
> + if expected_items and isinstance(expected_items, (list, tuple)):
> + check_output = True
> + expected_str = expected_items[0] or 'testpmd> '
> + else:
> + check_output = False
> + expected_str = expected_items or 'testpmd> '
> + timeout = int(item[2]) if len(item) == 3 else 5
> + #----------------------------------------------------------------
> + # run command on session
> + try:
> + console = self.testpmd.execute_cmd
> + msg_pipe = self.testpmd.get_output
> + output = console(item[0], expected_str, timeout)
> + output = 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 = 'close'
> + msg = "execute '{0}' timeout".format(item[0])
> + output = out = self.parent.dut.session.session.get_output_all()
> + self.logger.error(output)
> + raise Exception(msg)
> +
> + if len(cmds) > 1:
> + outputs.append(output)
> + else:
> + outputs = output
> + if check_output and len(expected_items) >= 2:
> + self.logger.info(output)
> + expected_output = expected_items[1]
> + check_type = True if len(expected_items) == 2 \
> + else expected_items[2]
> + if check_type and expected_output in output:
> + msg = "expected '{0}' is in output".format(expected_output)
> + self.logger.info(msg)
> + elif not check_type and expected_output not in output:
> + fmt = "unexpected '{0}' is not in output"
> + msg = fmt.format(expected_output)
> + self.logger.info(msg)
> + else:
> + status = "isn't in" if check_type else "is in"
> + msg = "[{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='', eal_param=''):
> + try:
> + self.testpmd.start_testpmd( core_mask,
> + param=' '.join(options),
> + eal_param=eal_param)
> + except TimeoutException:
> + # check if testpmd quit
> + try:
> + self.check_process_exist()
> + except Exception as e:
> + self.testpmd_status = 'close'
> + msg = "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 = []
> + time.sleep(1)
> +
> + def start_testpmd(self, eal_option=''):
> + if self.testpmd_status == 'running':
> + return
> + # boot up testpmd
> + hw_mask = 'all'
> + options = ''
> + self.preset_testpmd_cmds = ['port stop all', '', 15]
> + self.preset_testpmd(hw_mask, options, eal_param=eal_option)
> + self.testpmd_status = 'running'
> +
> + def stop_testpmd(self):
> + time.sleep(1)
> + testpmd_cmds =[['port stop all', '', 15],
> + ['show port stats all', ''],
> + ['stop', ''],]
> + output = self.d_console(testpmd_cmds)
> + time.sleep(1)
> + return output
> +
> + def close_testpmd(self):
> + if self.testpmd_status == 'close':
> + return None
> + output = 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 = 'close'
> + return output
> +
> + def start_ports(self, port='all'):
> + """
> + Start a port which the testpmd can see.
> + """
> + timeout = 12 if port=='all' else 5
> + cmds =[
> + ["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=['rx', 'tx']):
> + """
> + get one port statistics of testpmd
> + """
> + _portid = int(portid) if isinstance(portid, (str, unicode)) else portid
> + info = self.testpmd.get_pmd_stats(_portid)
> + _kwd = ["-packets", "-errors", "-bytes"]
> + stats = {}
> + if isinstance(flow, list):
> + for item in flow:
> + for item2 in _kwd:
> + name = item.upper() + item2
> + stats[name] = int(info[name])
> + elif isinstance(flow, (str, unicode)):
> + for item in _kwd:
> + name = flow.upper() + item
> + stats[name] = int(info[name])
> + else:
> + msg = '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 = {}
> + attrs = ['tx', 'rx']
> + for port_id in ports:
> + stats[port_id] = 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 = 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 = self.parent.tester.get_local_port(self.parent.dut_ports[port_id])
> + self.set_tester_port_status(intf, status)
> + time.sleep(5)
> + cur_status = self.get_port_info(port_id, 'link_status')
> + self.logger.info("port {0} is [{1}]".format(port_id, cur_status))
> + if cur_status != status:
> + self.logger.warning("expected status is
> + [{0}]".format(status))
> +
> + def set_dut_port_status(self, port_id, status):
> + opt = 'link-up' if status == 'up' else 'link-down'
> + # stop slave link by force
> + cmd = "set {0} port {1}".format(opt, port_id)
> + self.d_console(cmd)
> + time.sleep(5)
> + cur_status = self.get_port_info(port_id, 'link_status')
> + self.logger.info("port {0} is [{1}]".format(port_id, cur_status))
> + if cur_status != 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 = r"(?<=%s)%s" % (key_str, regx_str)
> + s = re.compile(pattern)
> + res = s.search(string)
> + if type(res).__name__ == 'NoneType':
> + msg = "{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 = r"(?<=%s)%s" % (key, regx_str)
> + s = re.compile(pattern)
> + res = s.search(string)
> + if type(res).__name__ == '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 <port num>'.
> + """
> + key_str, regx_str = args
> + out = self.d_console("show port info %d" % port_id)
> + find_value = 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 = {
> + '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 = 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 = args
> + find_value = 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 = args if isinstance(args[0], (list, tuple)) else [args]
> + for search_args in search_args:
> + try:
> + info = self.get_bonding_config(config_content, search_args)
> + break
> + except Exception as e:
> + self.logger.info(e)
> + else:
> + info = None
> +
> + return info
> +
> + def get_bonding_info(self, bond_port, info_types):
> + ''' Get the specified port information by its output message format '''
> + info_set = {
> + '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 = self.d_console("show bonding config %d" % bond_port)
> + if isinstance(info_types, (list or tuple)):
> + query_values = []
> + for info_type in info_types:
> + if info_type in info_set.keys():
> + find_value = self.get_info_from_bond_config(
> + config_content, info_set[info_type])
> + if info_type in ['active_slaves', 'slaves']:
> + find_value = [value for value in find_value.split(' ')
> + if value]
> + else:
> + find_value = None
> + query_values.append(find_value)
> + return query_values
> + else:
> + info_type = info_types
> + if info_type in info_set.keys():
> + find_value = self.get_info_from_bond_config(
> + config_content, info_set[info_type])
> + if info_type in ['active_slaves', 'slaves']:
> + find_value = [value for value in find_value.split(' ')
> + if value]
> + return find_value
> + else:
> + return None
> +
> + def get_active_slaves(self, bond_port):
> + primary_port = int(self.get_bonding_info(bond_port, 'primary'))
> + active_slaves = 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=0, socket=0, verify_detail=False):
> + """
> + Create a bonding device with the parameters you specified.
> + """
> + cmd = "create bonded device %d %d" % (mode, socket)
> + out = self.d_console(cmd)
> + err_fmt = "Create bonded device on mode [%d] socket [%d] failed"
> + self.verify("Created new bonded device" in out, err_fmt% (mode, socket))
> + fmts = [
> + "Created new bonded device net_bond_testpmd_[\d] on \(port ",
> + "Created new bonded device net_bonding_testpmd_[\d] on \(port ",
> + "Created new bonded device eth_bond_testpmd_[\d] on \(port "]
> + bond_port = self.get_value_from_str(fmts, "\d+", out)
> + bond_port = int(bond_port)
> +
> + if verify_detail:
> + out = self.d_console("show bonding config %d" % bond_port)
> + 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 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 = 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=False, expected_str='',
> + *slave_ports):
> + """
> + Add ports into the bonding device as slaves.
> + """
> + if len(slave_ports) <= 0:
> + utils.RED("No port exist when add slave to bonded device")
> + for slave_id in slave_ports:
> + cmd = "add bonding slave %d %d" % (slave_id, bond_port)
> + out = self.d_console(cmd)
> + if expected_str:
> + self.verify(expected_str in out,
> + "message <{0}> is missing".format(expected_str))
> + slaves = 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 = "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=False, *slave_port):
> + """
> + Remove the specified slave port from the bonding device.
> + """
> + if len(slave_port) <= 0:
> + msg = "No port exist when remove slave from bonded device"
> + self.logger.error(msg)
> + for slave_id in slave_port:
> + cmd = "remove bonding slave %d %d" % (int(slave_id), bond_port)
> + self.d_console(cmd)
> + slaves = 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 = (
> + "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 = self.get_bonding_info(bond_port, 'slaves')
> + if not all_slaves:
> + return
> + all_slaves = all_slaves.split()
> + if len(all_slaves) == 0:
> + return
> + self.remove_slaves(bond_port, False, *all_slaves)
> +
> + def set_primary_slave(self, bond_port, slave_port, invert_verify=False):
> + """
> + Set the primary slave for the bonding device.
> + """
> + cmd = "set bonding primary %d %d" % (slave_port, bond_port)
> + self.d_console(cmd)
> + out = 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 = "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 = "set bonding mode %d %d" % (mode, bond_port)
> + self.d_console(cmd)
> + mode_value = 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 = "set bonding mac_addr %s %s" % (bond_port, mac)
> + self.d_console(cmd)
> + new_mac = self.get_port_mac(bond_port)
> + self.verify(new_mac == mac, "Set bonding mac failed")
> +
> + def get_port_mac(self, bond_port, query_type):
> + bond_port_mac = 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 = "set bonding balance_xmit_policy %d %s" % (bond_port, policy)
> + self.d_console(cmd)
> + new_policy = self.get_bonding_info(bond_port, 'balance_policy')
> + policy = "BALANCE_XMIT_POLICY_LAYER" + policy.lstrip('l')
> + self.verify(new_policy == policy, "Set bonding balance policy
> + failed")
> +
> + @property
> + def is_perf(self):
> + return self.parent._enable_perf
> --
> 1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2019-02-28 11:00 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-28 5:50 [dts] [PATCH V1][pmd bonding]: common methods used by bonding suites yufengmx
2019-02-28 5:50 ` [dts] [PATCH V1]pmd_bonding: " yufengmx
2019-02-28 6:03 ` Mo, YufengX
2019-02-28 8:40 ` Chen, Zhaoyan
2019-02-28 11:00 ` Tu, Lijuan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).