[dts] [PATCH V1 2/6] pmd_bonded_8023ad: upload automation script

yufengx.mo at intel.com yufengx.mo at intel.com
Wed Jun 6 07:38:29 CEST 2018


From: yufengmx <yufengx.mo at intel.com>


This automation script is for pmd bonded 8023ad feature.

IEEE 802.3ad Dynamic link aggregation.  Creates aggregation groups that share
the same speed and duplex settings.  Utilizes all slaves in the active
aggregator according to the 802.3ad specification. Slave selection for outgoing
traffic is done according to the transmit hash policy.

Signed-off-by: yufengmx <yufengx.mo at intel.com>
---
 tests/TestSuite_pmd_bonded_8023ad.py | 2147 ++++++++++++++++++++++++++++++++++
 1 file changed, 2147 insertions(+)
 create mode 100644 tests/TestSuite_pmd_bonded_8023ad.py

diff --git a/tests/TestSuite_pmd_bonded_8023ad.py b/tests/TestSuite_pmd_bonded_8023ad.py
new file mode 100644
index 0000000..b9aa3f4
--- /dev/null
+++ b/tests/TestSuite_pmd_bonded_8023ad.py
@@ -0,0 +1,2147 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2018 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 random
+import inspect
+import struct
+import socket
+from socket import htons, htonl
+
+from packet import Packet, NVGRE, IPPROTO_NVGRE
+from scapy.sendrecv import sendp
+from scapy.utils import wrpcap, rdpcap, hexstr
+
+import utils
+from test_case import TestCase
+from exception import TimeoutException, SwitchException, VerifyFailure
+from settings import TIMEOUT
+from pmd_output import PmdOutput
+from settings import HEADER_SIZE
+from serializer import Serializer
+
+SOCKET_0 = 0
+SOCKET_1 = 1
+MODE_LACP = 4
+FRAME_SIZE_64 = 64
+
+#--------------------------------------------------
+# use for debug
+from pprint import pprint, pformat
+from functools import wraps
+import traceback
+import pdb
+
+import threading
+
+class DaemonThread(threading.Thread):
+    THREAD_TIMEOUT_MAX = 1e10
+
+    def __init__(self, func, name=None, **kwargs):
+        super(DaemonThread, self).__init__()
+        self._is_start = threading.Event()
+        self._is_stopped  = threading.Event()
+        self.func = func
+        self.daemon       = True
+        self.name         = name or self.__class__.__name__
+        self.kwargs = kwargs
+        self.start()
+
+    def on_crash(self, msg, *fmt, **kwargs):
+        #print(msg.format(*fmt), file=sys.stderr)
+        print msg.format(*fmt)
+        exc_info = sys.exc_info()
+        try:
+            traceback.print_exception(exc_info[0], 
+                                      exc_info[1], 
+                                      exc_info[2],
+                                      None, 
+                                      sys.stderr)
+        finally:
+            del(exc_info)
+
+    def run(self):
+        start_set = self._is_start.is_set
+        while not start_set():
+            time.sleep(0.1)
+        try:
+            try:
+                self.func(**self.kwargs)
+            except Exception as exc:
+                try:
+                    self.on_crash('{0!r} crashed: {1!r}', 
+                                  self.name, 
+                                  exc)
+                    self._set_stopped()
+                finally:
+                    # exiting by normal means won't work
+                    os._exit(1)
+        finally:
+            self._set_stopped()
+
+    def _set_stopped(self):
+        try:
+            self._is_stopped.set()
+        except TypeError:
+            # we lost the race at interpreter shutdown,
+            # so gc collected built-in modules.
+            pass
+
+    def activate(self):
+        """enter main executing loop"""
+        self._is_start.set()
+
+    def stop(self):
+        """Graceful shutdown."""
+        self._is_stopped.wait()
+        if self.is_alive():
+            self.join(self.THREAD_TIMEOUT_MAX)
+
+#############
+
+#############
+class TestBonding8023AD(TestCase):
+    AGG_MODES = ["bandwidth", "stable", "count"]
+    DEDICATED_QUEUES = ['disable', 'enable']
+    #
+    # On tester platform, packet transmission
+    #
+    def get_stats(self, portid, flow):
+        """
+        get testpmd port statistic
+        """
+        _portid = int(portid) if isinstance(portid, (str, unicode)) else portid
+        info = self.testpmd.get_pmd_stats(_portid)
+        _kwd = ["-packets", "-missed", "-bytes"]
+        kwd = map(lambda x: flow.upper() + x, _kwd) 
+        result =  [int(info[item]) for item in kwd]
+
+        return result
+
+    def config_tester_port(self, port_name, status):
+        """
+        Do some operations to the network interface port, 
+        such as "up" or "down".
+        """
+        if self.tester.get_os_type() == 'freebsd':
+            self.tester.admin_ports(port_name, status)
+        else:
+            eth = self.tester.get_interface(port_name)
+            self.tester.admin_ports_linux(eth, status)
+        time.sleep(5)
+
+    def config_tester_port_by_number(self, number, status):
+        # stop slave link by force 
+        cmd = "port stop %d"%number
+        self.d_console(cmd)
+        # stop peer port on tester
+        port_name = self.tester.get_local_port(self.dut_ports[number])
+        self.config_tester_port( port_name, status)
+        time.sleep(5)
+        cur_status = self.get_port_info(number, 'link_status')
+        self.logger.info("port {0} is [{1}]".format(number, cur_status))
+        if cur_status != status:
+            self.logger.warning("expected status is [{0}]".format(status))
+
+    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 src layer setting
+        ori_config = ('52:00:00:00:00:03', '10.239.129.65', 61)
+        mac, ip, port = ori_config
+        return (self.increase_mac(mac, step),
+                self.increase_ip(ip, step),
+                self.increase_port(port, step))
+
+    def set_stream2(self, stm_names=None):
+        ''' using packet.py module to create a stream '''
+        #----------------------------------------------------------------------
+        # set streams for traffic
+        pkt_configs = {
+        # UDP_1: 
+        #    Frame Data/Protocols: Ethernet 2 0800, IPv4,UDP/IP, Fixed 64.
+        #    IPv4 Header Page: Dest Address: 2.2.2.7 Src  Address: 2.2.2.3
+        #    UDP Header: Src Port: 32  Dest Port: 33
+        #
+        #    Stream Control: Stop after this Stream, Packet Count 32.
+        #
+        'UDP_1': {
+        'type': 'TCP',
+        'pkt_layers': {
+            #'ether': {'src': srcmac, 'dst': nutmac},
+            'ipv4': {'src': '2.2.2.3', 'dst': '2.2.2.7'},
+            'udp': {'src': 32, 'dst': 33},
+            'raw': {'payload': ['58'] * self.get_pkt_len('udp')}}},
+        }
+
+        # create packet for send
+        streams = []
+        for stm_name in stm_names:
+            if stm_name not in pkt_configs.keys():
+                continue
+            values = pkt_configs[stm_name]
+            # 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)
+            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 get_pkt_len(self, pkt_type):
+        # packet size
+        frame_size = FRAME_SIZE_64
+        headers_size = sum(map(lambda x: HEADER_SIZE[x],
+                               ['eth', 'ip', pkt_type]))
+        pktlen = frame_size - headers_size
+        return pktlen
+
+    def parse_ether_ip(self, dst_port, **ether_ip):
+        """
+        ether_ip:
+            'ether':'dst_mac':False
+                    'src_mac':"52:00:00:00:00:00"
+            'dot1q': 'vlan':1
+            'ip':   'dst_ip':"10.239.129.88"
+                    'src_ip':"10.239.129.65"
+            'udp':  'dst_port':53
+                    'src_port':53
+        """
+        ret_ether_ip = {}
+        ether = {}
+        dot1q = {}
+        ip = {}
+        udp = {}
+
+        try:
+            dut_dst_port = self.dut_ports[dst_port]
+        except Exception, e:
+            dut_dst_port = dst_port
+        # create src/dst mac address
+        if not ether_ip.get('ether'):
+            ether['dst_mac'] = self.dut.get_mac_address(dut_dst_port)
+            ether['src_mac'] = "52:00:00:00:00:00"
+        else:
+            # dst
+            if not ether_ip['ether'].get('dst_mac'):
+                ether['dst_mac'] = self.dut.get_mac_address(dut_dst_port)
+            else:
+                ether['dst_mac'] = ether_ip['ether']['dst_mac']
+            # src
+            if not ether_ip['ether'].get('src_mac'):
+                ether['src_mac'] = "52:00:00:00:00:00"
+            else:
+                ether['src_mac'] = ether_ip["ether"]["src_mac"]
+        # create src/dst dot1q
+        if not ether_ip.get('dot1q'):
+            pass
+        else:
+            if not ether_ip['dot1q'].get('vlan'):
+                dot1q['vlan'] = '1'
+            else:
+                dot1q['vlan'] = ether_ip['dot1q']['vlan']
+        # create src/dst ip address
+        if not ether_ip.get('ip'):
+            ip['dst_ip'] = "10.239.129.88"
+            ip['src_ip'] = "10.239.129.65"
+        else:
+            if not ether_ip['ip'].get('dst_ip'):
+                ip['dst_ip'] = "10.239.129.88"
+            else:
+                ip['dst_ip'] = ether_ip['ip']['dst_ip']
+            if not ether_ip['ip'].get('src_ip'):
+                ip['src_ip'] = "10.239.129.65"
+            else:
+                ip['src_ip'] = ether_ip['ip']['src_ip']
+        # create src/dst port number
+        if not ether_ip.get('udp'):
+            udp['dst_port'] = 53
+            udp['src_port'] = 53
+        else:
+            if not ether_ip['udp'].get('dst_port'):
+                udp['dst_port'] = 53
+            else:
+                udp['dst_port'] = ether_ip['udp']['dst_port']
+            if not ether_ip['udp'].get('src_port'):
+                udp['src_port'] = 53
+            else:
+                udp['src_port'] = ether_ip['udp']['src_port']
+
+        ret_ether_ip['ether'] = ether
+        ret_ether_ip['dot1q'] = dot1q
+        ret_ether_ip['ip'] = ip
+        ret_ether_ip['udp'] = udp
+
+        return ret_ether_ip
+
+    def set_stream(self, dst_port, src_port=False, frame_size=FRAME_SIZE_64,
+                    pkt_type='tcp', **slaves):
+        # get dst layer setting
+        dst_mac = self.get_port_info(dst_port, 'mac')
+        destport = 53
+        nutmac = dst_mac
+        destip = '10.239.129.88'
+        # packet size
+        pktlen = self.get_pkt_len(pkt_type)
+        self.packet_types = {}
+        for packet_id in range(len(slaves['active'])):
+            # src config
+            srcmac, srcip, srcport = self.increase_mac_ip_port(packet_id)
+            # config layer format
+            pkt = Packet(pkt_type=pkt_type.upper())
+            pkt.config_layer('ether', {'src': srcmac, 'dst': nutmac})
+            pkt.config_layer('ipv4', {'src': srcip, 'dst': destip})
+            pkt.config_layer('raw', {'payload': ['58'] * pktlen})
+            pkt.config_layer(pkt_type, {'src': srcport, 'dst': destport})
+            # generate stream
+            self.packet_types[packet_id] = pkt
+            # save a pcap file for debug convenience
+            savePath = os.sep.join([self.dut.base_dir,
+                                    "port_{0}.pcap".format(str(packet_id))])
+            pkt.pktgen.write_pcap(savePath)
+
+    def send_packet_quick(self, tx_iface, count=1, interval=0.01):
+        for pkt_id in sorted(self.packet_types.keys()):
+            pkt = self.packet_types[pkt_id].pktgen.pkt
+            sendp(pkt, iface=tx_iface, inter=interval, verbose=False, 
+                  count=count)
+            wait_time  = 0.0001
+
+    def send_pkt_multi_stream(self, intf, count):
+        sendp(self.pkt, iface=intf, count=count)
+
+    def send_packets_by_ixia(self, intf, count=1):
+        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.dut.base_dir, 'lacp_tx.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 = 64
+        # calculate number of packets
+        expect_pps = self.wirespeed(self.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.tester.get_local_port(self.dut_ports[0])
+        tgen_input.append((tester_port, 
+                           tester_port, 
+                           ixia_pkt))
+        # run latency stat statistics
+        rate_percent = self.rate_percent
+        self.tester.loop_traffic_generator_throughput(tgen_input,
+                                                      rate_percent)
+
+    def stop_ixia(self, data_types='packets'):
+        # get ixia statistics
+        line_rate = self.tester.get_port_line_rate()
+        rx_bps, rx_pps = \
+        self.tester.stop_traffic_generator_throughput_loop(self.tgen_input)
+        output = self.tester.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 send_packets(self, intf, pkts=None, interval=0.01 ,count=1):
+        send_pkts = []
+        for pkt in pkts:
+            send_pkts.append(pkt.pktgen.pkt)
+        sendp(send_pkts, iface=intf, inter=interval, 
+              verbose=False, count=count)
+
+    def send_multi_packet_quick(self, tx_iface, count=1):
+        self.send_packets(tx_iface, self.packet_types.values(), count=count)
+    #
+    # On dut, dpdk testpmd
+    #
+    def preset_testpmd(self, core_mask, options='', eal_param=''):
+        try:
+            self.testpmd.start_testpmd( core_mask, param=' '.join(options),
+                                        eal_param=eal_param)
+        # add exception for debug usage
+        except TimeoutException:
+            try:
+                self.check_process_exist() # used for debug
+            except Exception as e:
+                self.testpmd_status = 'close'
+            finally:
+                pass
+            msg = "execute '{0}' timeout".format(item[0])
+            self.logger.error(msg_pipe(timeout))
+            raise TimeoutException(msg)
+        finally:
+            pass
+
+        time.sleep(20)
+        # check if testpmd has bootep up
+        if not self.check_process_status():
+            raise VerifyFailure("testpmd boot up failed")
+        else:
+            self.logger.info("testpmd boot up sucessful")
+        self.d_console(self.preset_testpmd_cmds)
+        self.preset_testpmd_cmds = list()
+        time.sleep(1)
+
+    def check_process_status(self, process_name='testpmd'):
+        cmd = "ps aux | grep -i %s | grep -v grep | awk {'print $2'}"%(
+                                                                process_name)
+        out = self.dut.alt_session.send_expect(cmd, "# ", 10)
+        status = True if out != "" else False
+        return status
+    # use for debug
+    def check_process_exist(self, process_name='testpmd'):
+        status = self.check_process_status(process_name)
+        if not status:
+            msg = "{0} process quit exceptional".format(process_name)
+            out = self.dut.session.session.get_output_all()
+            self.logger.info(out)
+            raise VerifyFailure(msg)
+
+    def d_console(self, cmds):
+        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]
+        if len(cmds) > 1:
+            outputs = []
+        else:
+            outputs = ''
+        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:
+                    self.check_process_exist() # used for debug
+                except Exception as e:
+                    self.testpmd_status = 'close'
+                finally:
+                    pass
+                msg = "execute '{0}' timeout".format(item[0])
+                output = out = self.dut.session.session.get_output_all()
+                self.logger.error(output)
+                raise TimeoutException(msg)
+            finally:
+                pass
+            
+            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 start_testpmd(self, eal_option=''):
+        if self.testpmd_status == 'running':
+            return
+        if self.is_perf:
+            options = map(lambda x: "--" + x, [
+                               # 'burst=32',
+                               # 'rxfreet=32',
+                               # 'mbcache=250',
+                               # 'txpt=32',
+                               # 'rxht=8',
+                               # 'rxwt=0',
+                               # 'txfreet=32',
+                               # 'txrst=32',
+                               # 'txqflags=0xf01'
+                                 ])
+            #options = '' #TBD
+            offloadd = '0x1fbf' if self.driver == 'i40e' else '0x2203f'
+            options = ["--tx-offloads={0}".format(offloadd)]
+        else:
+            offloadd = '0x1fbf' if self.driver == 'i40e' else '0x2203f'
+            options = ["--tx-offloads={0}".format(offloadd)]
+        # link eal option and testpmd options
+        #options = [eal_option, options] if eal_option else [options]
+        # boot up testpmd
+        hw_mask = 'all'
+        #hw_mask = '1S/4C/1T'
+        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 sucessful")
+        self.testpmd_status = 'close'
+        return output
+
+    # 
+    # On dut, dpdk bonding
+    #
+    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':
+                self.logger.warning("{0} hasn't match anything".format(key_str))
+                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 ' '
+
+    # 
+    # dpdk link bonding
+    # 
+    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:
+            return None
+
+    def get_bonding_config(self, config_content, args):
+        """
+        Get info by executing the 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 the active slaves of the bonding device which you choose.
+        """
+        info = None
+
+        if isinstance(args[0], (list, tuple)):
+            search_args = args
+        else:
+            search_args = [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)
+            finally:
+                pass
+        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_all_stats(self, unbound_port, rx_tx, bond_port, **slaves):
+        """
+        Get all the port stats which the testpmd can display.
+        
+        :param unbound_port: pmd port id
+        :param rx_tx: unbond port stat 'rx' or 'tx'
+        :param bond_port: bonding port
+        :param slaves:
+                 'active' = []
+                 'inactive' = []
+        """
+        pkt_now = {}
+        bond_stat = 'tx' if rx_tx == 'rx' else 'rx'
+        if unbound_port: # if unbound_port has not been set, ignore this
+            pkt_now[unbound_port] = \
+                [int(_) for _ in self.get_stats(unbound_port, rx_tx)]
+            
+        pkt_now[bond_port] = \
+                [int(_) for _ in self.get_stats(bond_port, bond_stat)]
+        for slave in slaves['active']:
+            pkt_now[slave] = [int(_) for _ in self.get_stats(slave, bond_stat)]
+        for slave in slaves['inactive']:
+            pkt_now[slave] = [int(_) for _ in self.get_stats(slave, bond_stat)]
+
+        return pkt_now
+
+    def get_active_slaves(self, primary_slave, bond_port):
+        self.config_tester_port_by_number(primary_slave, "down")
+        primary_port = self.get_bonding_info(bond_port, 'primary')
+        active_slaves = self.get_bonding_info(bond_port, 'active_slaves')
+        if active_slaves and primary_port in active_slaves:
+            active_slaves.remove(primary_port)
+        else:
+            fmt = "primary port <{0}> isn't in active slaves list"
+            raise VerifyFailure(fmt.format(primary_port))
+
+        return primary_port, 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 start_ports(self, port='all'):
+        """
+        Start a port which the testpmd can see.
+        """
+        timeout = 12 if port=='all' else 5
+        # to avoid lsc event message interfere normal status
+        cmds =[]
+        cmds.append(["port start %s" % str(port), " ", timeout])
+        cmds.append([" ", '', timeout])
+        self.d_console(cmds)
+
+    def add_slave(self, bond_port, invert_verify=False, expected_str='',
+                  *slave_ports):
+        """
+        Add the 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 missiong".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:
+            utils.RED("No port exist when remove slave from bonded device")
+        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')
+        all_slaves = all_slaves.split()
+        if len(all_slaves) == 0:
+            pass
+        else:
+            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 mode for the bonding device.
+        """
+        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 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")
+
+    def set_8023ad_agg_mode(self, bond_port, mode="bandwidth"):
+        """
+        set bonding agg_mode <port_id> <agg_name>
+        
+        Set 802.11AD Aggregator Mode
+        """
+        cmd = "set bonding agg_mode %d %s" % (bond_port, mode)
+        self.d_console(cmd)
+        cur_mode = self.get_bonding_info(bond_port, 'agg_mode')
+        if mode == cur_mode:
+            fmt = "set bonding agg_mode <{0}> successfully"
+            self.logger.info(fmt.format(mode))
+        else:
+            msg = "failed to set bonding agg_mode <{0}>".format(mode)
+            self.logger.error(msg)
+            raise VerifyFailure(msg)
+
+    def get_8023ad_agg_mode(self, bond_port):
+        """
+        get bonding agg_mode <port_id> <agg_name>
+        
+        get 802.11AD Aggregator Mode
+        """
+        cur_mode = self.get_bonding_info(bond_port, 'agg_mode')
+        return cur_mode
+
+    def set_8023ad_dedicated_queue(self, bond_port, status='disable'):
+        """
+        set 802.11AD dedicated_queues status
+        enable|disable
+        """
+        cmds =[ ["set bonding lacp dedicated_queues %s %s" % (bond_port,
+                                                              status),
+                ['', 'port %s failed'%bond_port, False], 2],
+              ]
+        out = self.d_console(cmds)
+        # when set 'hw'
+        if status == 'enable':
+            expected_msg = 'queues for LACP control packets enabled'
+            err_fmt = "link bonding mode 4 (802.3ad) set {0} failed"
+            self.verify(expected_msg in out, err_fmt.format(status))
+        elif status == 'disable':
+            expected_msg = 'queues for LACP control packets disabled'
+            err_fmt = "link bonding mode 4 (802.3ad) set {0} failed"
+            self.verify(expected_msg in out, err_fmt.format(status))
+        else:
+            pass
+
+    def get_8023ad_dedicated_queues(self, bond_port):
+        """
+        get 802.11AD dedicated_queues status
+        enable|disable
+        """
+        status = self.get_bonding_info(bond_port, 'dedicated_queues')
+        return status
+
+    def set_bond_port_ready(self, tx_port, bond_port):
+        # there is a issue of core dump, 2017.0822
+        cmd= "set portlist {0},{1}".format(tx_port, bond_port)
+        self.d_console(cmd)
+        # for port link up is slow and unstable, 
+        # every port should start one by one
+        start_fmt = "port start {0}".format
+        cmds = []
+        port_num = len(self.dut_ports)
+        for cnt in range(port_num):
+            cmds.append([start_fmt(cnt), '', 5])
+        self.d_console(cmds)
+        time.sleep(10)
+        self.d_console([start_fmt(self.bond_port), '', 15])
+        time.sleep(5)
+        self.d_console(["start", '', 10])
+        self.logger.info("set bond port ready done !!!")
+
+    def set_8023ad_dedicated_traffic(self):
+        # If RX fing full free lacpdu message and drop packet
+        pass
+
+    def set_8023ad_bonded(self, slaves, bond_mode):
+        ''' set stacked bonded mode for the specified bonding mode '''
+        specified_socket = SOCKET_0
+        # create bonded device 1, add slaves in it
+        bond_port = self.create_bonded_device(bond_mode, specified_socket)
+        # when no slave attached, mac should be 00:00:00:00:00:00
+        self.bonding_8023ad_check_macs_without_slaves(bond_port)
+        # add slave
+        self.add_slave(bond_port, False, '', *slaves)
+        # check if master bonding/each slaves queue configuration is the same.
+        ports = slaves + [bond_port]
+        return bond_port
+
+    def run_8023ad_pre(self, slaves, bond_mode):
+        bond_port = self.set_8023ad_bonded(slaves, bond_mode)
+        # should set port to stop and make sure port re-sync with parter
+        cmds = ["port stop all", '', 15]
+        self.d_console(cmds)
+        time.sleep(2)
+        cmds = ["port start all", '', 10]
+        self.d_console(cmds)
+        time.sleep(2)
+        return bond_port
+
+    def get_bond_port_mac(self, bond_port, query_type):
+        bond_port_mac = self.get_port_info(bond_port, query_type)
+        return bond_port_mac
+
+    def bonding_8023ad_check_macs_without_slaves(self, bond_port):
+        ''' check if bonded device's mac is one of its slaves macs '''
+        query_type = 'mac'
+        bond_port_mac = self.get_bond_port_mac(bond_port, query_type)
+        default_mac = '00:00:00:00:00:00'
+        if bond_port_mac == default_mac:
+            msg = "bond port default mac is [{0}]".format(default_mac)
+            self.logger.info(msg)
+        else:
+            fmt = "bond port default mac is [{0}], not expected mac"
+            msg = fmt.format(bond_port_mac)
+            self.logger.warning(msg)
+
+    def bonding_8023ad_check_macs(self, slaves, bond_port):
+        ''' check if bonded device's mac is one of its slaves macs '''
+        query_type = 'mac'
+        bond_port_mac = self.get_bond_port_mac(bond_port, query_type)
+        if bond_port_mac == '00:00:00:00:00:00':
+            msg = "bond port hasn't set mac address"
+            self.logger.info(msg)
+            return
+        
+        for port_id in slaves:
+            slave_mac = self.get_port_info(port_id, query_type)
+            if bond_port_mac == slave_mac:
+                fmt = "bonded device's mac is slave [{0}]'s mac [{1}]"
+                msg = fmt.format(port_id, slave_mac)
+                self.logger.info(msg)
+                return port_id
+        else:
+            fmt = "bonded device's current mac [{0}] " + \
+                  "is not one of its slaves macs"
+            msg = fmt.format(bond_port_mac)
+            # it is not supported by dpdk, but supported by linux normal 
+            # bodning/lacp tool
+            self.logger.warning('bonding_8023ad_check_macs: ' + msg)
+
+    def check_bonded_device_mac_change(self, slaves, bond_port):
+        remove_slave = 0
+        cur_slaves = slaves[1:]
+        self.remove_slaves(bond_port, *[remove_slave])
+        self.bonding_8023ad_check_macs(cur_slaves, bond_port)
+
+    def check_slave_mac_restore(self, slave, bond):
+        query_type = 'mac'
+        slave_old_mac = self.get_bond_port_mac(slave, query_type)
+        self.remove_slave_from_bonding_device(bond, False, 
+                                              self.dut_ports[2])
+
+    def check_bonded_device_start(self, bond_port):
+        cmds = [["port stop all", '', 15]]
+        portList = [bond_port]
+        cmds +=[["port start %s"%bond_port, '', 10],
+                ["start", [' ', 'core dump', False]]]
+        self.d_console(cmds)
+        time.sleep(2)
+        return bond_port
+
+    def check_bonded_device_up_down(self, bond_port):
+        # stop bonded device
+        cmds = ["port stop {0}".format(bond_port), '']
+        self.d_console(cmds)
+        status = self.get_port_info(bond_port, 'link_status')
+        if status != 'down':
+            msg = "bond port {0} fail to set down".format(bond_port)
+            self.logger.error(msg)
+            raise VerifyFailure(msg)
+        else:
+            msg = "bond port {0} set down successful !".format(bond_port)
+            self.logger.info(msg)
+        # start bond port
+        cmds = ["port start {0}".format(bond_port), '', 10]
+        self.d_console(cmds)
+        status = self.get_port_info(bond_port, 'link_status')
+        if status != 'up':
+            msg = "bond port {0} fail to set up".format(bond_port)
+            self.logger.error(msg)
+            raise VerifyFailure(msg)
+        else:
+            msg = "bond port {0} set up successful !".format(bond_port)
+            self.logger.info(msg)
+
+    def check_bonded_device_promisc_mode(self, slaves, bond_port):
+        # close bonded device promiscuous mode
+        cmds = [["set promisc {0} off".format(bond_port), '']]
+        time.sleep(3)
+        self.d_console(cmds)
+        status = self.get_port_info(bond_port, 'promiscuous_mode')
+        if status != 'disabled':
+            fmt = "bond port {0} fail to set promiscuous mode disabled"
+            msg = fmt.format(bond_port)
+            self.logger.warning(msg)
+        else:
+            fmt = "bond port {0} set promiscuous mode disabled successful !"
+            msg = fmt.format(bond_port)
+            self.logger.info(msg)
+        # check slave promiscuous status
+        for port_id in slaves:
+            status = self.get_port_info(port_id, 'promiscuous_mode')
+            if status != 'disabled':
+                fmt = ("slave port {0} promiscuous mode "
+                      "isn't the same as bond port 'disabled'")
+                msg = fmt.format(port_id)
+                self.logger.error(msg)
+                raise VerifyFailure(msg)
+            else:
+                fmt = "slave port {0} promiscuous mode is 'disabled' too"
+                msg = fmt.format(port_id)
+                self.logger.info(msg)
+        # open bonded device promiscuous mode
+        cmds = [["set promisc {0} on".format(bond_port), '']]
+        self.d_console(cmds)
+        time.sleep(3)
+        status = self.get_port_info(bond_port, 'promiscuous_mode')
+        if status != 'enabled':
+            fmt = "bond port {0} fail to set promiscuous mode enabled"
+            msg = fmt.format(bond_port)
+            self.logger.error(msg)
+            raise VerifyFailure(msg)
+        else:
+            fmt = "bond port {0} set promiscuous mode enabled successful !"
+            msg = fmt.format(bond_port)
+            self.logger.info(msg)
+        # check slave promiscuous status
+        for port_id in slaves:
+            status = self.get_port_info(port_id, 'promiscuous_mode')
+            if status != 'enabled':
+                fmt = "slave port {0} promiscuous mode " + \
+                      "isn't the same as bond port 'enabled'"
+                msg = fmt.format(port_id)
+                self.logger.error(msg)
+                raise VerifyFailure(msg)
+            else:
+                fmt = "slave port {0} promiscuous mode is 'enabled' too"
+                msg = fmt.format(port_id)
+                self.logger.info(msg)
+
+    def get_agg_mode_fmt(self):
+        retStatus = False
+        # if agg mode has added to cmdline.c
+        target_file = os.sep.join([self.dut.base_dir, 'app/test-pmd/cmdline.c'])
+        with open(target_file, 'rb') as fp:
+            if 'agg_mode' in fp.read():
+                retStatus = True
+
+        if retStatus:
+            agg_config = 'agg_mode={0}'
+            msg = "agg_mode has been merged"
+            self.logger.warning(msg)
+            #raise VerifyFailure(msg)
+        else:
+            self.logger.info("has no agg_mode such option")
+            agg_config = ''
+
+        return agg_config
+
+    def check_8023ad_agg_modes(self, slaves, bond_mode):
+        # check aggregator mode
+        #---------------------------
+        check_results = []
+        default_agg_mode = 'stable'
+        for mode in self.AGG_MODES:
+            try:
+                self.start_testpmd()
+                bond_port = self.set_8023ad_bonded(slaves,
+                                                   bond_mode)
+                cur_agg_mode = self.get_8023ad_agg_mode(bond_port)
+                
+                if cur_agg_mode != default_agg_mode:
+                    fmt = ("link bonding mode 4 (802.3ad) default agg mode "
+                          "isn't {0}")
+                    msg = fmt.format(default_agg_mode)
+                    self.logger.warning(msg)
+                # ignore default mode
+                if mode == cur_agg_mode:
+                    fmt = ("link bonding mode 4 (802.3ad) "
+                          "current agg mode is {0}")
+                    msg = fmt.format(mode)
+                    self.logger.info(msg)
+                    continue
+                #----------------
+                # set test pmd
+                cmds = []
+                cmds = [["port stop all", '', 15]]
+                portList = [bond_port]
+                cmds +=[["port start all", '', 15]]
+                self.d_console(cmds)
+                #----------------
+                self.set_8023ad_agg_mode(bond_port, mode)
+            except Exception as e:
+                check_results.append(e); print traceback.format_exc()
+            finally:
+                self.close_testpmd()
+                time.sleep(2)
+        #---------------------------
+        if check_results:
+            for e in check_results:
+                self.logger.error(e)
+            raise VerifyFailure('check_8023ad_agg_modes is failed')
+        return
+
+    def check_8023ad_packet_transmission(self, slaves, bond_mode):
+        # check aggregator mode
+        #---------------------------
+        check_results = []
+        default_agg_mode = 'stable'
+        for mode in self.AGG_MODES:
+            try:
+                bond_port = self.run_8023ad_pre(slaves, mode)
+                # ignore default mode
+                if mode == default_agg_mode:
+                    continue
+                self.set_8023ad_agg_mode(bond_port, mode)
+                # do packet transmission
+            except Exception as e:
+                check_results.append(e); print traceback.format_exc()
+            finally:
+                self.close_testpmd()
+                time.sleep(2)
+        #---------------------------
+        if check_results:
+            for e in check_results:
+                self.logger.error(e)
+            raise VerifyFailure('check_8023ad_packet_transmission is failed')
+        return
+
+    def check_8023ad_dedicated_queues(self, slaves, bond_mode):
+        # check aggregator mode
+        #---------------------------
+        check_results = []
+        default_slow_queue = 'unknown'
+        for mode in self.DEDICATED_QUEUES:
+            try:
+                self.start_testpmd()
+                bond_port = self.set_8023ad_bonded(slaves, bond_mode)
+                self.set_8023ad_dedicated_queue(bond_port, mode)
+            except Exception as e:
+                check_results.append(e); print traceback.format_exc()
+            finally:
+                self.close_testpmd()
+                time.sleep(2)
+        #---------------------------
+        if check_results:
+            for e in check_results:
+                self.logger.error(e)
+            raise VerifyFailure('check_8023ad_dedicated_queues is failed')
+        return
+
+    def check_8023ad_dedicated_queues_transmission(self, slaves, bond_mode):
+        # check aggregator mode
+        #---------------------------
+        check_results = []
+        default_slow_queue = 'unknown'
+        for mode in self.DEDICATED_QUEUES:
+            try:
+                self.start_testpmd()
+                bond_port = self.set_8023ad_bonded(slaves,
+                                                   bond_mode)
+                #cur_slow_queue = self.get_8023ad_slow_queue(bond_port)
+                #if cur_slow_queue != default_slow_queue:
+                #    msg = "link bonding mode 4 (802.3ad) default slow queue 
+                #   isn't {0}".format(default_slow_queue)
+                #    self.logger.warning(msg)
+                # ignore default mode
+                #if mode != default_slow_queue:
+                self.set_8023ad_agg_mode(bond_port, mode)
+                #----------------
+                pass
+            except Exception as e:
+                check_results.append(e); print traceback.format_exc()
+            finally:
+                self.close_testpmd()
+                time.sleep(2)
+        #---------------------------
+        if check_results:
+            for e in check_results:
+                self.logger.error(e)
+            msg = 'check_8023ad_dedicated_queues_transmission is failed'
+            raise VerifyFailure(msg)
+        return
+
+    ###############################
+    # testpmd other command
+    ###############################
+    def start_all_ports(self):
+        """
+        Start all the ports which the testpmd can see.
+        """
+        self.start_port("all")
+
+    def start_port(self, port):
+        """
+        Start a port which the testpmd can see.
+        """
+        cmd ="port start %s" % str(port)
+        self.d_console(cmd)
+        time.sleep(3)
+
+    def switch_daemon_config(self, **kwargs):
+        if self.switch_name == 'quanta':
+            return
+        port_id = kwargs.get('port_id')
+        console = kwargs.get('console')
+        wait_time = kwargs.get('wait_time')
+        time.sleep(wait_time)
+        self.logger.info(console.get_stats())
+        console.set_intf_down(port_id)
+        self.logger.info(console.get_stats())
+
+    def create_intf_down_daemon(self, sw_scene, port_id, wait_time):
+        para = {'port_id': port_id,
+                'wait_time': wait_time,
+                'console': sw_scene}
+        daemon = DaemonThread( self.switch_daemon_config,
+                               name="switch", **para)
+        return daemon
+
+    def check_8023ad_rx(self, unbound_port, bond_port, **slaves):
+        """Verify that receiving packets correctly in the mode 4.
+        
+        :param unbound_port: the unbonded port id
+        :param bond_port: the bonded device port id
+        :param slaves:
+                 'active':[]
+                 'inactive':[]
+        """
+        pass
+
+    def run_switch_pre(self):
+        sw_scene = self.sw_scene
+        sw_scene.reset()
+        sw_ports = sw_scene.ports()
+        # set one random port as slave down port 
+        # if salve ports are more than three.
+        slave_down_id = random.randint(0, len(sw_ports) - 1)
+        sw_port_id = sw_ports[0]
+        #[scene.set_intf_up(port_id) for port_id in sw_ports]
+        sw_scene.get_stats()
+        wait_time = 10
+        switch_daemon = self.create_intf_down_daemon(sw_scene, sw_port_id,
+                                                     wait_time)
+        return sw_scene, switch_daemon, sw_ports
+
+    def traffic(self, bond_port, slaves):
+        pkt_count = 1000
+        pkt_now = {}
+        multi_stream = "/home/myf/multi.log"
+        down = "/home/myf/down.log"
+        #----------------------------
+        # create stream for traffic
+        tx_port = self.tx_port
+        self.set_stream( bond_port, src_port=tx_port, pkt_type='udp', **slaves)
+        if not os.path.exists(down):
+            switch_daemon = None
+        if self.is_perf:
+            pkt_gen_type = 'ixia'
+            pkt_generator = self.send_packets_by_ixia
+        elif os.path.exists(multi_stream):
+            pkt_gen_type = 'scapy'
+            os.remove(multi_stream)
+            pkt_generator = self.send_multi_packet_quick # send multi packet
+        else:
+            pkt_gen_type = 'scapy'
+            pkt_generator = self.send_packet_quick
+        time.sleep(3)
+        #----------------------------
+        # run traffic
+        self.logger.info("begin transmission data......")
+        try:
+            pkt_generator(tx_port, pkt_count)
+            if self.switch_name == 'quanta':
+                loop_count = 5
+                wait = loop_count/3
+                interval = 15
+                #interval = 1
+                time.sleep(wait*interval)
+                wait_time = (loop_count -wait)*interval
+                self.logger.info("wait {0}".format(wait_time))
+                time.sleep(wait_time)
+            #------------------------------------
+            if pkt_gen_type == 'scapy':
+                pkt_now = self.get_all_stats(None, "tx", bond_port, 
+                                             **slaves)
+                self.logger.info("batch packet transmission data")
+                for port_id in sorted(pkt_now.keys()):
+                    values = [str(value).rjust(10) 
+                                for value in pkt_now[port_id]]
+                    msg =  "port {0}: ".format(port_id) + ",".join(values)
+                    self.logger.info(msg)
+        except Exception as e:
+            msg = traceback.format_exc()
+            self.logger.error(msg)
+        finally:
+            pass
+        #------------------------------
+        # end traffic
+        if self.is_perf:
+            self.stop_ixia()
+        self.logger.info("complete transmission")
+
+    def traffic_with_random_slave_down(self, bond_port, slaves):
+        pkt_count = 1000
+        pkt_now = {}
+        multi_stream = "/home/myf/multi.log"
+        down = "/home/myf/down.log"
+        #----------------------------
+        # create stream for traffic
+        tx_port = self.tx_port
+        self.set_stream(bond_port, src_port=tx_port, pkt_type='udp', **slaves)
+        if not os.path.exists(down):
+            switch_daemon = None
+        if self.is_perf:
+            pkt_generator = self.send_packets_by_ixia
+        elif os.path.exists(multi_stream):
+            os.remove(multi_stream)
+            pkt_generator = self.send_multi_packet_quick # send multi packet
+        else:
+            pkt_generator = self.send_packet_quick
+        time.sleep(3)
+        cnt = 0
+        #----------------------------
+        # run traffic
+        self.logger.info("begin transmission data......")
+        wait_time = ''
+        loop_count = 5
+        while cnt < loop_count:
+            try:
+                if os.path.exists(quit_file):
+                    os.remove(quit_file)
+                    break
+                ##################################
+                pkt_generator(tx_port, pkt_count)
+                if self.switch_name == 'quanta':
+                    wait = loop_count/3
+                    #interval = 50
+                    interval = 1
+                    time.sleep(wait*interval)
+                    if self.slave_down:
+                        # add random wait time to get a scatter sample data
+                        random_wait_time = random.randint(1, 20)
+                        #time.sleep(random_wait_time)
+                    wait_time = (loop_count -wait)*interval
+                    self.logger.info("wait {0}".format(wait_time))
+                    time.sleep(wait_time)
+                    break
+                else:
+                    if cnt == loop_count/3:
+                        if switch_daemon:
+                            switch_daemon.activate()
+                #------------------------------------
+                #pkt_total = pkt_total + pkt_count*len(sw_ports)
+                if False:
+                    pkt_now = self.get_all_stats(None, "tx", bond_port, 
+                                                 **slaves)
+                    self.logger.info("batch packet transmission data")
+                    for port_id in sorted(pkt_now.keys()):
+                        values = [str(value).rjust(10) 
+                                    for value in pkt_now[port_id]]
+                        msg =  "port {0}: ".format(port_id) + ",".join(values)
+                        self.logger.info(msg)
+            except Exception as e:
+                msg = traceback.format_exc()
+                self.logger.error(msg)
+            finally:
+                pass
+            cnt += 1
+        #-------------------------------------------------------------
+        # end traffic
+        # stop ixia
+        if self.is_perf:
+            self.stop_ixia()
+        else:
+            if switch_daemon:
+                switch_daemon.stop()
+        self.logger.info("complete transmission")
+
+    def verify_8023ad_tx(self, tx_ports, bond_port, **slaves):
+        """Verify that transmitting the packets correctly in the lacp mode."""
+        if self.switch_status == 'active':
+            self.d_console("stop")
+            sw_scene, switch_daemon, sw_ports = self.run_switch_pre()
+            self.d_console("start")
+        #-------------------------------------------------------------
+        # run traffic
+        self.traffic(bond_port, slaves)
+        #-------------------------------------------------------------
+        time.sleep(3)
+        if self.switch_status == 'active':
+            sw_scene.stop()
+            switch_stats = sw_scene.get_stats()
+            self.cur_data['switch statistics'] = switch_stats
+        self.logger.warning("batch packet transmission data")
+
+    def get_switch_port(self, dut_port_id):
+        ''' get switch port name corresponding to dut port id '''
+        peer = self.dut.ports_info[dut_port_id]['peer']
+        sw_port = peer.split(":")[1] if 'switch' in peer else None
+        return sw_port
+
+    def get_switch_keys(self, key):
+        if self.switch_name == 'quanta':
+            keys_table = {'rx ucast': 'RX Ucast Pkts',
+                          'tx ucast': 'TX Ucast Pkts'}
+        elif self.switch_name == 'cisco':
+            keys_table = {'RX-packets': '',
+                          'TX-packets': ''}
+        else:
+            return None
+        return keys_table[key]
+
+    def check_sample_data(self, case_name):
+        expected_rate = 1/10e4
+        summary_msg = []
+        for mode in self.data_results[case_name]:
+            data = self.data_results[case_name][mode]
+            pmd_stats = data['testpmd ports statistics']
+            switch_stats = data['switch statistics']
+            # check slave traffic stats
+            port_msg = []
+            sw_total_rx = 0
+            for dut_port_id in pmd_stats:
+                pmd_stat = pmd_stats[dut_port_id]
+                sw_port_name = self.get_switch_port(dut_port_id)
+                if not sw_port_name:
+                    continue
+                switch_stat = switch_stats[sw_port_name]
+                # check each slave's traffic loss
+                # lacpdu packet is calculated by testpmd , so there is more 
+                # pkts number on testpmd statistics
+                port_text = "dut port [{0}]".format(dut_port_id)
+                if sw_port_name:
+                    pmd_tx = pmd_stat['TX-packets']
+                    key = 'rx ucast'
+                    sw_rx = switch_stat[self.get_switch_keys(key)]
+                    sw_total_rx += sw_rx
+                    rate = 1 - float(sw_rx)/float(pmd_tx)
+                    msg = port_text + \
+                         " traffic loss {0} is more than expected".format(rate)
+                    if rate > expected_rate:
+                        port_msg.append(msg) 
+                else:
+                    msg = port_text + " has not corresponding switch port"
+                    port_msg.append()
+
+            # check total fwd traffic loss of bonding device
+            pmd_fwd_stats = data['testpmd fwd statistics']
+            bond_port_id = self.bond_port
+            tx_port_id = None
+            for dut_port_id in pmd_fwd_stats:
+                if dut_port_id != bond_port_id:
+                    pmd_fwd_tx = pmd_fwd_stats[dut_port_id]['RX-packets']
+                    tx_port_id = dut_port_id
+                    break
+            pmd_bond_rx = pmd_fwd_stats[bond_port_id]['TX-packets']
+            fwd_msg = []
+            if pmd_bond_rx < pmd_fwd_tx:
+                rate = 1 - float(pmd_bond_rx)/float(pmd_fwd_tx)
+                port_text = "dut port [{0}] fwd to bond port [{1}]".format(
+                                                                tx_port_id,
+                                                                bond_port_id)
+                msg = port_text + \
+                     " traffic loss {0} is more than expected".format(rate)
+                if rate > expected_rate:
+                    fwd_msg.append(msg) 
+            # check total traffic loss of bonding device
+            # 
+            bond_msg = []
+            if sw_total_rx == 0 or pmd_fwd_tx == 0:
+                msg = "total packet is zero, transmission not happen"
+                bond_msg.append(msg)
+            elif sw_total_rx < pmd_fwd_tx:
+                rate = 1 - float(sw_total_rx)/float(pmd_fwd_tx)
+                port_text = "bond port [{0}] to switch".format(bond_port_id)
+                msg = port_text + \
+                     " traffic loss {0} is more than expected".format(rate)
+                if rate > expected_rate:
+                    bond_msg.append(msg)
+            # check status
+            if fwd_msg or bond_msg:
+                mode_msg = "mode {0}".format(mode)
+                summary_msg.append(mode_msg)
+                summary_msg += port_msg +  fwd_msg + bond_msg
+        if summary_msg:
+            self.logger.error(os.linesep.join(summary_msg))
+            return True
+        else:
+            self.logger.info('sample data are ok')
+            return False
+
+    def get_pci_link(self):
+        # get forwarding port
+        # TBD, unkown usage
+        tx_pci = []
+        for port_info in self.dut.ports_info:
+            tx_pci.append(port_info['pci'])
+        if not tx_pci:
+            msg = "can't find tx_port pci"
+            self.logger.error(msg)
+            raise VerifyFailure(msg)
+        #-------------------
+        # get bonding ports configuration
+        slaves = self.dut_ports[:]
+        slave_pcis = []
+        slave_ids = []
+        for port_id in slaves:
+            slave_pcis.append(self.dut.ports_info[port_id]['pci'])
+            slave_ids.append(port_id)
+        return slave_ids, slave_pcis
+
+    def get_pci_link_with_switch(self):
+        # get forwarding port
+        tx_pci = []
+        for port_info in self.dut.ports_info:
+            if 'switch' not in port_info['peer']:
+                tx_pci.append(port_info['pci'])
+        if not tx_pci:
+            msg = "can't find tx_port pci"
+            self.logger.error(msg)
+            raise VerifyFailure(msg)
+        #-------------------
+        # get bonding ports configuration
+        slaves = self.dut_ports[:]
+        slave_pcis = []
+        slave_ids = []
+        for port_id in slaves:
+            if 'switch' in self.dut.ports_info[port_id]['peer']:
+                slave_pcis.append(self.dut.ports_info[port_id]['pci'])
+                slave_ids.append(port_id)
+        return slave_ids, slave_pcis
+
+    def get_commandline_options(self, agg_mode):
+        # get bonding ports configuration
+        if self.is_perf:
+            slave_ids, slave_pcis = self.get_pci_link_with_switch()
+        else:
+            slave_ids, slave_pcis = self.get_pci_link()
+        # get nic configuration
+        bonding_name = 'net_bonding0'
+        slaves_pci = ["slave=" + pci for pci in slave_pcis]
+        bonding_mode = 'mode={0}'.format(str(MODE_LACP))
+        agg_config = 'agg_mode={0}'
+        vdev_format = ",".join([bonding_name] + slaves_pci + \
+                               [bonding_mode, agg_config])
+        # begin check command line options
+        check_results = []
+        mode = str(MODE_LACP)
+        options = vdev_format.format(agg_mode)
+        vdev_options = " --vdev '{0}'".format(options)
+        bond_port = len(self.dut_ports)
+        return bond_port, vdev_options
+
+    def run_test_pre(self, agg_mode):
+        msgs = []
+        if self.switch_status == 'active':
+            self.tester.ixia_packet_gen.clean_ownership()
+            self.sw_scene.clear() # clear switch statistics
+        # get bonding ports configuration
+        bond_port, vdev_options = self.get_commandline_options(agg_mode)
+        self.bond_port = bond_port
+        # boot up testpmd
+        self.start_testpmd(eal_option=vdev_options)
+        cur_slaves, cur_agg_mode = self.get_bonding_info(bond_port,
+                                            ['slaves', 'agg_mode'])
+        if agg_mode != cur_agg_mode:
+            fmt = 'expected agg mode is [{0}], current agg mode is [{1}]'
+            msg = fmt.format(agg_mode, cur_agg_mode)
+            msgs.append(msg)
+        #-------------------
+        # get forwarding port
+        #-------------------
+        tx_port_id = ''
+        for port_id in range(bond_port):
+            if str(port_id) not in cur_slaves:
+                tx_port_id = port_id
+                break
+        else:
+            tx_port_id = bond_port
+        # raise VerifyFailure
+        if msgs:
+            for msg in msgs:
+                self.logger.warning(msg)
+            fmt = 'fail to config from command line at {0}'
+            msg = fmt.format(agg_mode)
+            self.logger.warning(msg)
+            #raise VerifyFailure(msg)
+        #-----------------------------------------
+        # open dedicated queue
+        self.set_8023ad_dedicated_queue(bond_port, 'enable')
+        if self.switch_status == 'active':
+            self.sw_scene.start()
+        self.set_bond_port_ready(tx_port_id, bond_port)
+        slaves = [int(slave) for slave in cur_slaves]
+
+        return bond_port, slaves, tx_port_id
+
+    def run_test_post(self, bond_port, tx_port_id):
+        slave_stats = {}
+        for port_id in range(bond_port):
+            if tx_port_id == port_id or bond_port == port_id:
+                continue
+            slave_stats[port_id] = self.testpmd.get_pmd_stats(port_id)
+
+        self.cur_data['testpmd ports statistics'] = slave_stats
+        #-------------
+        fwd_pmd_stats = {}
+        for port_id in [bond_port, tx_port_id]:
+            fwd_pmd_stats[port_id] = self.testpmd.get_pmd_stats(port_id)
+        self.cur_data['testpmd fwd statistics'] = fwd_pmd_stats
+        output = self.close_testpmd()
+        self.sw_scene.clear()
+        self.tester.ixia_packet_gen.clean_ownership()
+
+    def run_dpdk_pre2(self):
+        slaves = self.dut_ports[:]
+        self.start_testpmd()
+        mode = MODE_LACP
+        bond_port = self.run_8023ad_pre(slaves, mode)
+        return slaves, bond_port
+
+    def run_dpdk_post2(self):
+        self.close_testpmd()
+        return True
+
+    def check_traffic_with_cmd_line_options(self, agg_mode='count'):
+        # begin check command line options
+        check_results = []
+        max_loop = self.sample_number
+        cur_case_name = self.cur_case
+        sample_results = {}
+        for cnt in range(max_loop):
+            self.data_results[cur_case_name] = {}
+            case_data = self.data_results[cur_case_name]
+            #for agg_mode in self.AGG_MODES:
+            if agg_mode in self.AGG_MODES:
+                case_data[agg_mode] = {}
+                self.cur_data = case_data[agg_mode]
+                self.logger.info('begin to check {0}'.format(agg_mode))
+                bond_port, cur_slaves, tx_port_id = self.run_test_pre(agg_mode)
+                try:
+                    #-----------------------------------------
+                    # begin loop sending packet transmission
+                    slaves = {}
+                    slaves['active'] = cur_slaves
+                    slaves['inactive'] = []
+                    tx_ports =[self.tx_port]
+                    self.verify_8023ad_tx(tx_ports, bond_port, **slaves)
+                except Exception as e:
+                    check_results.append(e); print traceback.format_exc()
+                finally:
+                    pass 
+                self.run_test_post(bond_port, tx_port_id)
+            # check sample data, if there are exception, mark it and put it on
+            # result list
+            try:
+                status = self.check_sample_data(cur_case_name)
+                if status:
+                    sample_results[cnt] = status
+            except Exception as e:
+                sample_results[cnt] = 'data absence'
+            finally:
+                pass
+
+        if sample_results:
+            check_results.append(pformat(sample_results, indent=1, width=1))
+        
+        if check_results:
+            for e in check_results:
+                self.logger.error(e)
+            raise VerifyFailure('test_command_line_option is failed')
+        self.logger.info("traffic good")
+
+        return
+
+    def check_cmd_line_option_status(self, agg_mode, bond_port, slaves):
+        mode = str(MODE_LACP)
+        msgs = []
+        cur_mode, cur_slaves, cur_active_slaves, cur_agg_mode =\
+                self.get_bonding_info(bond_port, 
+                                       ['mode', 
+                                        'slaves', 
+                                        'active_slaves', 
+                                        'agg_mode'])
+        #---------------------------------
+        # check bonding mode
+        if mode != cur_mode:
+            fmt = 'expected mode is [{0}], current mode is [{1}]'
+            msg = fmt.format(mode, cur_mode)
+            msgs.append(msg)
+        #---------------------------------
+        # check bonding 802.3ad agg mode
+        if agg_mode != cur_agg_mode:
+            fmt ='expected agg mode is [{0}], current agg mode is [{1}]'
+            msg = fmt.format(agg_mode, cur_agg_mode)
+            msgs.append(msg)
+        #---------------------------------
+        # check bonded slaves
+        _cur_slaves = [int(id) for id in cur_slaves]
+        if not _cur_slaves or cmp(sorted(slaves), sorted(_cur_slaves)) != 0:
+            slaves_str = ' '.join([str(id) for id in slaves])
+            cur_slaves_str = ' '.join([str(id) for id in _cur_slaves]) \
+                                        if _cur_slaves else ''
+            msg_format = 'expected slaves is [{0}], current slaves is [{1}]'
+            msg = msg_format.format(slaves_str, cur_slaves_str)
+            msgs.append(msg)
+        #---------------------------------
+        # check active slaves status before ports start
+        if self.kdriver is 'i40e':
+            if cur_active_slaves:
+                check_active_slaves = [int(id) for id in cur_active_slaves]
+                if cmp(sorted(slaves), sorted(check_active_slaves)) != 0:
+                    slaves_str = ' '.join([str(id) for id in slaves])
+                    msg_fmt = ('expected active slaves is [{0}], '
+                              'current active slaves is [{1}]')
+                    msg = msg_fmt.format(slaves_str, cur_active_slaves)
+                    msgs.append(msg)
+            else:
+                msg = 'active slaves should not be empty'
+                self.logger.warning(msg)
+                #msgs.append(msg)
+        else:
+            if cur_active_slaves:
+                msg = 'active slaves should be empty'
+                self.logger.warning(msg)
+                #msgs.append(msg)
+        #---------------------------------
+        # check status after ports start
+        self.start_ports()
+        # set bonded device to active status
+        if self.kdriver is not 'i40e':
+            cur_active_slaves = [int(id) for id in self.get_bonding_info(
+                                                            bond_port, 
+                                                            'active_slaves')]
+            if not cur_active_slaves or cmp(sorted(slaves), 
+                                            sorted(cur_active_slaves)) != 0:
+                slaves_str = ' '.join([str(id) for id in slaves])
+                active_str = ' '.join([str(id) for id in cur_active_slaves]) \
+                                               if cur_active_slaves else ''
+                msg_fmt = ('expected active slaves is [{0}], '
+                          'current active slaves is [{1}]')
+                msg = msg_fmt.format(slaves_str, active_str)
+                msgs.append(msg)
+        #---------------------------------
+        # raise exception
+        if msgs:
+            for msg in msgs:
+                self.logger.warning(msg)
+            msg = 'fail to config from command line at {0}'.format(agg_mode)
+            raise VerifyFailure(msg)
+
+    def verify_tx(self):
+        """Verify that transmitting the packets correctly in the lacp mode. """
+        pkt_count = 1000
+        pkt_total = 0
+        pkt_now = {}
+        loop_count = 5
+        cnt = 0
+        tx_port = self.tx_port
+        bond_port = 0
+        slaves = {}
+        slaves['active'] =['0', '1','2','3']
+        self.set_stream(bond_port, src_port=tx_port, pkt_type='udp', **slaves)
+        #------------------------------------------------------------
+        pkt_generator = self.send_packets_by_ixia
+        self.logger.info("begin transmission data......")
+        wait_time = 30*1
+        #------------------------------------------------------------
+        try:
+            ##################################
+            pkt_generator(tx_port, pkt_count)
+            time.sleep(wait_time)
+        except Exception as e:
+            msg = traceback.format_exc()
+            self.logger.error(msg)
+        finally:
+            pass
+
+        # stop ixia
+        self.stop_ixia()
+        return
+
+    @property
+    def is_perf(self):
+        return self._enable_perf
+    
+    @property
+    def is_switch(self):
+        return self.tester.has_switch()
+
+    @property
+    def driver(self):
+        return self.kdriver
+    #
+    # Test cases.
+    #
+    def set_up_all(self):
+        """
+        Run before each test suite
+        """
+        self.verify('bsdapp' not in self.target, "Bonding not support freebsd")
+        #------------------------------------------------------------
+        # link peer resource
+        self.dut_ports = self.dut.get_ports()
+        required_link = 5 if self.is_switch else 2
+        self.verify(len(self.dut_ports) >= required_link, "Insufficient ports")
+        self.ports_socket = self.dut.get_numa_id(self.dut_ports[0])
+        self.all_cores_mask = utils.create_mask(self.dut.get_core_list("all"))
+        #------------------------------------------------------------
+        # stream configs
+        self.stream_dst_configs = []
+        #------------------------------------------------------------
+        # testpmd related
+        self.testpmd = PmdOutput(self.dut)
+        self.testpmd_status = 'close'
+        #------------------------------------------------------------
+        # 802.3ad related
+        self.tester_bond = "bond0"
+        self.agg_mode = None
+        self.bond_port = None
+        #--------------------------------
+        # switch related
+        # only itecStvDts02 platform support lacp testing
+        #tester_hostname = socket.gethostname()
+        if self.is_switch:
+            self.tx_port = self.tester.get_interface(
+                                self.tester.get_local_port(self.dut_ports[0]))
+            switch_name = 'quanta'
+            if 'lacp_group' not in self.tester.switch_scenes:
+                msg = "[lacp_group] section not set in switch.cfg"
+                raise SwitchException(msg)
+            self.sw_scene = self.tester.switch_scenes['lacp_group']
+            self.switch_name = switch_name
+            self.switch_status = 'active'
+            #---------------------------------
+            self.multi_stream_flg = False
+            self.add_options = False
+            self.slave_down = False
+        else:
+            self.switch_status = 'close'
+        # use for sample long time pressure testing
+        self.sample_number = 1
+        #--------------------------------
+        # traffic related
+        self.packet_types = {}
+        #----------
+        # ixia
+        self.rate_percent = float(100)
+        #------------------------------------------------------------------
+        # use for debug
+        self.data = []
+        self.cur_data = {}
+        self.data_results = {}
+        self.cur_case = 'lacp'
+
+    def set_up(self):
+        """
+        Run before each test case.
+        """
+        pass
+
+    def tear_down(self):
+        """
+        Run after each test case.
+        """
+        try:
+            self.close_testpmd()
+        except Exception as e:
+            pass
+        finally:
+            pass
+
+    def tear_down_all(self):
+        """
+        Run after each test suite.
+        """
+        if self.switch_status == 'active':
+            self.sw_scene.quit()
+            self.switch_status = 'close'
+
+    def test_basic_behav_startStop(self):
+        '''
+        test 802.3ad basic behavior(port start/stop)
+        '''
+        #----------------------------
+        msg = ''
+        slaves, bond_port = self.run_dpdk_pre2()
+        try:
+            for _ in range(10):
+                self.check_bonded_device_start(bond_port)
+        except Exception as e:
+            msg = "bonding 8023ad check start/stop failed"
+        finally:
+            pass
+        self.run_dpdk_post2()
+        if msg:
+            raise VerifyFailure(msg)
+        return
+
+    def test_basic_behav_mac(self):
+        '''
+        test 802.3ad basic behavior(mac address)
+        '''
+        #----------------------------
+        msg = ''
+        slaves, bond_port = self.run_dpdk_pre2()
+        try:
+            self.bonding_8023ad_check_macs(slaves, bond_port)
+            self.check_bonded_device_mac_change(slaves, bond_port)
+        except Exception as e:
+            msg = "bonding 8023ad check macs failed"
+        finally:
+            pass
+        self.run_dpdk_post2()
+        if msg:
+            raise VerifyFailure(msg)
+        return
+
+    def test_basic_behav_upDown(self):
+        '''
+        test 802.3ad basic behavior(link up/down)
+        '''
+        msg = ''
+        slaves, bond_port = self.run_dpdk_pre2()
+        try:
+            self.check_bonded_device_up_down(bond_port)
+        except Exception as e:
+            msg = "bonding 8023ad check link up/down failed"
+        finally:
+            pass
+        self.run_dpdk_post2()
+        if msg:
+            raise VerifyFailure(msg)
+        return
+
+    def test_basic_behav_promisc_mode(self):
+        '''
+        test 802.3ad basic behavior(promisc mode)
+        '''
+        msg = ''
+        slaves, bond_port = self.run_dpdk_pre2()
+        try:
+            self.check_bonded_device_promisc_mode(slaves, bond_port)
+        except Exception as e:
+            msg = "bonding 8023ad check promisc mode failed"
+        finally:
+            pass
+        self.run_dpdk_post2()
+        if msg:
+            raise VerifyFailure(msg)
+        return
+
+    def test_command_line_option(self):
+        '''
+        test 802.3ad basic behavior(bonded configs using command line option)
+        '''
+        for agg_mode in self.AGG_MODES:
+            bond_port, cur_slaves, tx_port_id = self.run_test_pre(agg_mode)
+            self.check_cmd_line_option_status(agg_mode, bond_port, cur_slaves)
+            self.close_testpmd()
+
+    def test_basic_behav_agg_mode(self):
+        slaves = self.dut_ports[:]
+        mode = MODE_LACP
+        self.check_8023ad_agg_modes(slaves, mode)
+        return
+
+    def test_basic_dedicated_queues(self):
+        slaves = self.dut_ports[:]
+        mode = MODE_LACP
+        self.check_8023ad_dedicated_queues(slaves, mode)
+        return
+
+    def check_perf_tx(self, agg_mode):
+        #--------------------------------------------------------------------
+        if self.switch_status == 'close':
+            raise VerifyFailure("no switch support this testing case")
+        self.slave_down = False
+        #================================
+        # select agg mode
+        #-------------------
+        # create command line options
+        self.check_traffic_with_cmd_line_options(agg_mode=agg_mode)
+        return
+
+    def test_perf_agg_count_tx(self):
+        self.check_perf_tx("count")
+
+    def test_perf_agg_stable_tx(self):
+        self.check_perf_tx("stable")
+
+    def test_perf_agg_bandwidth_tx(self):
+        self.check_perf_tx("bandwidth")
\ No newline at end of file
-- 
1.9.3



More information about the dts mailing list