test suite reviews and discussions
 help / color / mirror / Atom feed
* [dts] [PATCH V1 0/6] pmd_bonded_8023ad: upload test plan
@ 2018-06-06  5:38 yufengx.mo
  2018-06-06  5:38 ` [dts] [PATCH V1 1/6] " yufengx.mo
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: yufengx.mo @ 2018-06-06  5:38 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

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

*. extend ixia to send continuous stream 
*. support switch equipment auto query and configure running parameters on dts framework 
*. pmd_bonded_8023ad test plan 
*. pmd_bonded_8023ad automation script 

yufengmx (6):
  pmd_bonded_8023ad: upload test plan
  pmd_bonded_8023ad: upload automation script
  pmd_bonded_8023ad: add switch module in dts/framework
  pmd_bonded_8023ad: dts configuration files
  pmd_bonded_8023ad: framework work flow
  pmd_bonded_8023ad: framework etgen/ixia

 conf/crbs.cfg                              |    2 +
 conf/ports.cfg                             |    2 +
 conf/switch.cfg                            |   27 +
 framework/config.py                        |   61 +-
 framework/dts.py                           |   20 +-
 framework/dut.py                           |   14 +-
 framework/etgen.py                         |  125 +-
 framework/exception.py                     |   10 +
 framework/logger.py                        |   24 +-
 framework/project_dpdk.py                  |    6 +-
 framework/settings.py                      |    7 +-
 framework/ssh_connection.py                |    9 +-
 framework/ssh_pexpect.py                   |   36 +-
 framework/switch.py                        | 1445 +++++++++++++++++++
 framework/tester.py                        |  115 +-
 test_plans/pmd_bonded_8023ad_test_plan.rst |  521 +++++++
 tests/TestSuite_pmd_bonded_8023ad.py       | 2147 ++++++++++++++++++++++++++++
 17 files changed, 4555 insertions(+), 16 deletions(-)
 create mode 100644 conf/switch.cfg
 create mode 100644 framework/switch.py
 mode change 100755 => 100644 framework/tester.py
 create mode 100644 test_plans/pmd_bonded_8023ad_test_plan.rst
 create mode 100644 tests/TestSuite_pmd_bonded_8023ad.py

-- 
1.9.3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [dts] [PATCH V1 1/6] pmd_bonded_8023ad: upload test plan
  2018-06-06  5:38 [dts] [PATCH V1 0/6] pmd_bonded_8023ad: upload test plan yufengx.mo
@ 2018-06-06  5:38 ` yufengx.mo
  2018-07-06  1:30   ` Liu, Yong
  2018-06-06  5:38 ` [dts] [PATCH V1 2/6] pmd_bonded_8023ad: upload automation script yufengx.mo
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 9+ messages in thread
From: yufengx.mo @ 2018-06-06  5:38 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 17790 bytes --]

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


This test plan 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@intel.com>
---
 test_plans/pmd_bonded_8023ad_test_plan.rst | 521 +++++++++++++++++++++++++++++
 1 file changed, 521 insertions(+)
 create mode 100644 test_plans/pmd_bonded_8023ad_test_plan.rst

diff --git a/test_plans/pmd_bonded_8023ad_test_plan.rst b/test_plans/pmd_bonded_8023ad_test_plan.rst
new file mode 100644
index 0000000..d871323
--- /dev/null
+++ b/test_plans/pmd_bonded_8023ad_test_plan.rst
@@ -0,0 +1,521 @@
+.. Copyright (c) <2010-2018>, Intel Corporation
+   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.
+
+Link Bonding for mode 4 (802.3ad)
+=================================
+
+This test plan is mainly to test link bonding mode 4(802.3ad) function via 
+testpmd
+
+link bonding mode 4 is 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. DPDK 
+realize it based on 802.1AX specification, it includes LACP protocal and Marker 
+protocol. This mode requires a switch that supports IEEE 802.3ad Dynamic link 
+aggregation.
+
+note: Slave selection for outgoing traffic is done according to the transmit 
+hash policy, which may be changed from the default simple XOR layer2 policy.
+
+**Requirements**
+
+* Bonded ports SHALL maintain statistics similar to that of normal ports
+
+* The slave links SHALL be monitor for link status change. See also the concept 
+  of up/down time delay to handle situations such as a switch reboots, it is 
+  possible that its ports report "link up" status before they become usable.
+
+* Upon unbonding the bonding PMD driver MUST restore the MAC addresses that the 
+  slaves had before they were enslaved.
+
+* According to the bond type, when the bond interface is placed in promiscuous
+  mode it will propagate the setting to the slave devices.
+
+* Generally require that the switch should be compatible with IEEE 802.3AD.
+  e.g. Cisco 5500 series with EtherChannel support or may be called a trunk 
+  group.
+
+* LACP control packet filtering offload. It is a idea of performance 
+  improvement, which use hardware offloads to improve packet classification. 
+  
+  technical details refer to content attached in website
+  http://dpdk.org/ml/archives/dev/2017-May/066143.html
+
+*.support three 802.3ad aggregation selection logic modes (stable/bandwidth/
+  count). The Selection Logic selects a compatible Aggregator for a port, using
+  the port�s LAG ID. The Selection Logic may determine that the link should be
+  operated as a standby link if there are constraints on the simultaneous 
+  attachment of ports that have selected the same Aggregator.
+  
+  DPDK technical details refer to
+    ``doc/guides/prog_guide/link_bonding_poll_mode_drv_lib.rst`` 
+        ``Link Aggregation 802.3AD (Mode 4)``
+
+  Linux technical details refer to ``linux_bonding.txt`` content of 802.3ad
+
+Prerequisites for Bonding
+=========================
+*. additional hardware requirements
+   a switch that supports IEEE 802.3ad Dynamic link aggregation
+
+*. hardware configuration
+  all link ports of switch/dut should be the same data rate and support 
+  full-duplex.
+
+Functional testing hardware configuration
+-----------------------------------------
+  NIC and DUT ports requriements.
+  - Tester: 2 ports of nic
+  - DUT:    2 ports of nic
+
+ Connections ports between tester and DUT
+           Tester                           DUT
+          .-------.                      .-------. 
+          | port0 | <------------------> | port0 |
+          | port1 | <------------------> | port1 |
+          '-------'                      '-------'
+
+Performance testing hardware configuration
+------------------------------------------
+  NIC/DUT/IXIA/SWITCH ports requriements.
+  - Tester: 5 ports of nic.
+    niantic (2x10G) x 3
+  - IXIA:   1 ixia ports.
+        10G port
+  - SWITCH: 4 switch ports.
+    quanta hp_t3048(10G) / software: ONS CLI 1.0.1.1316-2
+
+    Connections ports between IXIA and DUT
+    -----------------------------------------------------------------
+                       quanta switch                               DUT
+                        .---------.                      |
+                        |   S xe1 | <------------------> | port0 (niantic)  <---> |
+                        |   W xe2 | <------------------> | port1 (niantic)  <---> |
+    - port-channel <--> |   I     |                      |                        |------> bond_port(port 5)
+                        |   T xe3 | <------------------> | port2 (niantic)  <---> |            ^
+                        |   C xe4 | <------------------> | port3 (niantic)  <---> |            |
+                        |   H     |                      |                                     |fwd
+                        '---------'                      |                                     |
+                                                         |                                     |
+                       ixia 10G                          |                                     |
+                |  slot 6 port 5  |  ------------------> | port4 (niantic)----------------------
+
+
+Test Case : basic behavior start/stop
+=====================================
+*. check bonded device stop/start action under frequecy operation status
+
+steps::
+*. bind two ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2>
+
+*. boot up testpmd
+    
+    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
+
+*. run testpmd command of bonding
+
+    testpmd> port stop all
+    testpmd> create bonded device 4 0
+    testpmd> add bonding slave 0 2
+    testpmd> add bonding slave 1 2
+ 
+*. loop execute this step 10 times, check if bonded device still work 
+
+    testpmd> port stop all
+    testpmd> port start all
+    testpmd> start
+    testpmd> show bonding config 2
+    testpmd> stop
+
+*. quit testpmd
+    testpmd> stop
+    testpmd> quit
+
+Test Case : basic behavior mac
+==============================
+*. bonded device's default mac is one of each slave's mac after one slave has 
+   been added.
+*. when no slave attached, mac should be 00:00:00:00:00:00
+*. slave's mac restore the MAC addresses that the slave has before they were 
+   enslaved.
+
+steps::
+*. bind two ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2>
+
+*. boot up testpmd
+    
+    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
+
+*. run testpmd command of bonding
+
+    testpmd> port stop all
+    testpmd> create bonded device 4 0
+ 
+*. check bond device mac should be 00:00:00:00:00:00
+
+    testpmd> show bonding config 2
+
+*. add two slaves to bond port
+    
+    testpmd> add bonding slave 0 2
+    testpmd> add bonding slave 1 2
+    testpmd> port start all
+
+*. check bond device mac should be one of each slave's mac
+
+    testpmd> show bonding config 0
+    testpmd> show bonding config 1
+    testpmd> show bonding config 2
+
+*. quit testpmd
+    testpmd> stop
+    testpmd> quit
+
+Test Case : basic behavior link up/down
+=======================================
+*. bonded device should be down status without slaves
+*. bonded device device should have the same status of link status
+*. Active Slaves status should change with the slave status change
+
+steps::
+*. bind two ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2>
+
+*. boot up testpmd
+    
+    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
+
+*. run testpmd command of bonding
+
+    testpmd> port stop all
+    testpmd> create bonded device 4 0
+    testpmd> add bonding slave 0 2
+    testpmd> add bonding slave 1 2
+
+*. stop bonded device and check bonded device/slaves link status
+
+    testpmd> port stop 2
+    testpmd> show bonding config 2
+    testpmd> show bonding config 1
+    testpmd> show bonding config 0
+
+*. start bonded device and check bonded device/slaves link status
+
+    testpmd> port start 2
+    testpmd> show bonding config 2
+    testpmd> show bonding config 1
+    testpmd> show bonding config 0
+
+*. quit testpmd
+    testpmd> stop
+    testpmd> quit
+
+Test Case : basic behavior promisc mode
+=======================================
+*. bonded device promiscuous mode should be ``enabled`` by default
+*. bonded device/slave device should have the same status of promiscuous mode
+
+steps::
+*. bind two ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2>
+
+*. boot up testpmd
+    
+    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
+
+*. run testpmd command of bonding
+
+    testpmd> port stop all
+    testpmd> create bonded device 4 0
+ 
+*. check if bonded device promiscuous mode is ``enabled``
+
+    testpmd> show bonding config 2
+
+*. add two slaves and check if promiscuous mode is ``enabled``
+
+    testpmd> add bonding slave 0 2
+    testpmd> add bonding slave 1 2
+    testpmd> show bonding config 0
+    testpmd> show bonding config 1
+
+*. disable bonded device promiscuous mode and check promiscuous mode
+
+    testpmd> set promisc 2 off
+    testpmd> show bonding config 2
+
+*. enable bonded device promiscuous mode and check promiscuous mode
+
+    testpmd> set promisc 2 on
+    testpmd> show bonding config 2
+
+*. check slaves' promiscuous mode
+
+    testpmd> show bonding config 0
+    testpmd> show bonding config 1
+
+*. quit testpmd
+    testpmd> stop
+    testpmd> quit
+
+Test Case : basic behavior agg mode
+===================================
+*. stable is the default agg mode
+*. check 802.3ad aggregation mode configuration
+support <agg_option>:
+``count``
+``stable``
+``bandwidth``
+
+steps::
+*. bind two ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2>
+
+*. boot up testpmd
+    
+    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
+
+*. run testpmd command of bonding
+
+    testpmd> port stop all
+    testpmd> create bonded device 4 0
+    testpmd> add bonding slave 0 2
+    testpmd> add bonding slave 1 2
+    testpmd> port start all
+    testpmd> show bonding config 2
+    testpmd> set bonding agg_mode 2 <agg_option>
+ 
+*. check if agg_mode set successful
+
+    testpmd> show bonding config 2
+        Bonding mode: 4
+        IEEE802.3AD Aggregator Mode: <agg_option>
+        Slaves (2): [0 1]
+        Active Slaves (2): [0 1]
+        Primary: [0]
+
+*. quit testpmd
+    testpmd> stop
+    testpmd> quit
+
+Test Case : basic behavior dedicated queues
+===========================================
+*. check 802.3ad dedicated queues is ``disable`` by default
+*. check 802.3ad set dedicated queues
+support <agg_option>:
+``disable``
+``enable``
+
+steps:
+*. bind two ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2>
+
+*. boot up testpmd
+    
+    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
+
+*. run testpmd command of bonding
+
+    testpmd> port stop all
+    testpmd> create bonded device 4 0
+    testpmd> add bonding slave 0 2
+    testpmd> add bonding slave 1 2
+    testpmd> show bonding config 2
+ 
+*. check if dedicated_queues disable successful
+
+    testpmd> set bonding lacp dedicated_queues 2 disable
+    
+*. check if bonded port can start
+
+    testpmd> port start all
+    testpmd> start
+ 
+*. check if dedicated_queues enable successful
+
+    testpmd> stop
+    testpmd> port stop all
+    testpmd> set bonding lacp dedicated_queues 2 enable
+
+*. check if bonded port can start
+
+    testpmd> port start all
+    testpmd> start
+
+*. quit testpmd
+    testpmd> stop
+    testpmd> quit
+
+Test Case : command line option
+===============================
+*. check command line option
+slave=<0000:xx:00.0>
+agg_mode=<bandwidth | stable | count> 
+*. compare bonding configuration with expected configuration.
+
+steps:
+*. bind two ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2>
+
+
+*. boot up testpmd 
+
+    ./testpmd -c 0x0f -n 4 \
+    --vdev 'net_bonding0,slave=0000:xx:00.0,slave=0000:xx:00.1,mode=4,agg_mode=<agg_option>'  \
+    -- -i --port-topology=chained
+
+*. run testpmd command of bonding
+
+    testpmd> port stop all
+
+*. check if bonded device has been created and slaves have been bonded successful 
+
+    testpmd> show bonding config 2
+        Bonding mode: 4
+        IEEE802.3AD Aggregator Mode: <agg_option>
+        Slaves (2): [0 1]
+        Active Slaves (2): [0 1]
+        Primary: [0]
+
+*. check if bonded port can start
+
+    testpmd> port start all
+    testpmd> start
+ 
+*. check if dedicated_queues enable successful
+
+    testpmd> stop
+    testpmd> port stop all
+
+*. quit testpmd
+    testpmd> quit
+
+
+Test Case : tx agg mode stable
+==============================
+stable: use slaves[default_slave] as index
+        The active aggregator is chosen by largest aggregate
+        bandwidth.
+
+        Reselection of the active aggregator occurs only when all
+        slaves of the active aggregator are down or the active
+        aggregator has no slaves.
+
+steps:
+*. quanta switch setting
+    vlan 100
+    port-channel 4000
+    slave interface: xe1/xe2/xe3/xe4
+
+*. dut port 1-4 link to quanta switch xe1/xe2/xe3/xe4
+
+*. dut port 5 link to ixia
+
+*. bind five ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2> \
+    <pci address 3> <pci address 4> <pci address 5>
+
+*. boot up testpmd with 4 slave ports
+
+    ./testpmd -c 0x0f -n 4 \
+    --vdev 'net_bonding0,slave=0000:xx:00.0,slave=0000:xx:00.1,slave=0000:xx:00.2,slave=0000:xx:00.3,mode=4,agg_mode=stable' \
+    -- -i --port-topology=chained
+
+*. packet setting, udp packet(in folder "stream_abcd")
+
+    [Ether(dst=nutmac, src=srcmac)/IP(dst=destip, src=srcip, len=46)/UDP(sport=srcport, dport=destport)/Raw(load='P'*26)
+    
+    create flow_a/flow_b/flow_c/flow_d stream flow
+
+*. start ixia traffic
+
+    ixia_stream=(flow_a+flow_b+flow_c+flow_d)
+    10G line rate run at percentPacketRate(100%)
+    traffic lasting 250 second or so
+
+*. run testpmd command of bonding, ixia traffic is forward from port 4 to bond port 5
+
+    testpmd> port stop all
+    testpmd> set bonding lacp dedicated_queues 5 enable
+    testpmd> set portlist 0,5
+    testpmd> port start all
+    testpmd> start
+
+*. keep ixia traffic lasting 5 minutes
+
+*. stop ixia and get ixia statistcis
+
+*. stop testpmd and get ixia statistcis
+
+    testpmd> stop
+    testpmd> port stop all
+    testpmd> show port stats all
+
+*. get quanta switch xe1/xe2/xe3/xe4 statistcis
+
+*. compare switch statistcis with testpmd statistcis
+
+Test Case : tx agg mode count
+=============================
+count:  use agg_count amount as index
+        The active aggregator is chosen by the largest number of
+        ports (slaves).  Reselection occurs as described under the
+        "bandwidth/count mode aggregator reselection".
+
+steps are the same as ``tx agg mode count``,  change the testpmd command as
+
+    ./testpmd -c 0x0f -n 4 \
+    --vdev 'net_bonding0,slave=0000:xx:00.0,slave=0000:xx:00.1,slave=0000:xx:00.2,slave=0000:xx:00.3,mode=4,agg_mode=count' \
+    -- -i --port-topology=chained
+
+Test Case : tx agg mode bandwidth
+=================================
+bandwidth: use link_speed amount as index
+        The active aggregator is chosen by largest aggregate
+        bandwidth. Reselection occurs as described under the
+        "bandwidth/count mode aggregator reselection".
+
+steps are the same as ``tx agg mode count``,  change the testpmd command as
+
+    ./testpmd -c 0x0f -n 4 \
+    --vdev 'net_bonding0,slave=0000:xx:00.0,slave=0000:xx:00.1,slave=0000:xx:00.2,slave=0000:xx:00.3,mode=4,agg_mode=bandwidth' \
+    -- -i --port-topology=chained
\ No newline at end of file
-- 
1.9.3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [dts] [PATCH V1 2/6] pmd_bonded_8023ad: upload automation script
  2018-06-06  5:38 [dts] [PATCH V1 0/6] pmd_bonded_8023ad: upload test plan yufengx.mo
  2018-06-06  5:38 ` [dts] [PATCH V1 1/6] " yufengx.mo
@ 2018-06-06  5:38 ` yufengx.mo
  2019-01-21  7:19   ` Chen, Zhaoyan
  2018-06-06  5:38 ` [dts] [PATCH V1 3/6] pmd_bonded_8023ad: add switch module in dts/framework yufengx.mo
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 9+ messages in thread
From: yufengx.mo @ 2018-06-06  5:38 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

From: yufengmx <yufengx.mo@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@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

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [dts] [PATCH V1 3/6] pmd_bonded_8023ad: add switch module in dts/framework
  2018-06-06  5:38 [dts] [PATCH V1 0/6] pmd_bonded_8023ad: upload test plan yufengx.mo
  2018-06-06  5:38 ` [dts] [PATCH V1 1/6] " yufengx.mo
  2018-06-06  5:38 ` [dts] [PATCH V1 2/6] pmd_bonded_8023ad: upload automation script yufengx.mo
@ 2018-06-06  5:38 ` yufengx.mo
  2018-06-06  5:38 ` [dts] [PATCH V1 4/6] pmd_bonded_8023ad: dts configuration files yufengx.mo
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: yufengx.mo @ 2018-06-06  5:38 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

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


support to query and configure switch equipment running parameters/statistics.
Currently, support quanta switch model t3048-iz1, which is a 10G switch
equipment. This module support to auto configure a 802.3ad running environment
and query statistics data.

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 framework/switch.py | 1445 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1445 insertions(+)
 create mode 100644 framework/switch.py

diff --git a/framework/switch.py b/framework/switch.py
new file mode 100644
index 0000000..d006f76
--- /dev/null
+++ b/framework/switch.py
@@ -0,0 +1,1445 @@
+# 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 sys
+import re
+import time
+from abc import abstractmethod
+
+from config import SwitchConf
+from logger import getLogger
+from ssh_connection import SSHConnection
+from exception import TimeoutException, ConfigParseException, SwitchException
+
+################################################
+# use for put switch console on background, control it using queue.
+# it is thread safe
+import traceback
+
+join_l = os.linesep.join
+
+class QuantaONS(object):
+    '''quanta switch
+    
+    Intel Open Network Software (ONS)
+    '''
+    NAME = 'Quanta switch'
+    MAX_PORTS = None
+    VLAN_RANGE = None
+    PORT_CHANNEL_RANGE = None
+    def __init__(self, *args, **kwargs):
+        self.console = kwargs.get('console')
+        self.logger = kwargs.get('logger')
+        # use for static port attribute
+        self._cache = {}
+    ########################################################################
+    #### utils method
+    ########################################################################
+    def filter_one_attrs(self, output):
+        '''deal with one section output message format as
+            
+            Port .................................... 2
+        '''
+        pat = '(.*) \.+ (.*)\r'
+        data = re.findall(pat, output, re.M)
+        stats = dict(data)
+        num_pat = '^\d+$'
+        for key in stats.keys():
+            value = stats[key]
+            flg = re.match(num_pat, value)
+            if flg:
+                stats[key] = int(value)
+        return stats
+
+    def filter_ports_attr(self, content):
+        '''deal with multiple section output message format as
+            
+            Port .................................... 1
+            
+            Port .................................... 2
+        '''
+        info = {}
+        sections =content.split("\r\n\r\n")[1].split("                       ")
+        for output in sections:
+            stats = self.filter_one_attrs(output)
+            if not stats:
+                continue
+            info[stats['Port']] = stats
+
+        return info
+
+    def filter_pchs_attr(self, content):
+        '''deal with multiple section output message format as
+            
+            Port Channel ............................ lag4000
+        '''
+        info = {}
+        sections =content.split("\r\n\r\n")[1].split("                       ")
+        for output in sections:
+            stats = self.filter_one_attrs(output)
+            if not stats:
+                continue
+            info[stats['Port Channel']] = stats
+
+        return info
+
+    def filter_one_section(self, content):
+        '''deal with one running-config message section'''
+        info = content.split("                       ")
+        _info = [ item.strip() for item in info if item.strip()]
+        attrs = map(lambda x: x.replace("   ", "").splitlines(), _info)
+        return attrs
+
+    def filter_interfaces_config(self, output):
+        '''deal with multiple section running-config message'''
+        patIntf = r'(?<=  interface).+?(?=exit)'
+        sections = re.findall(patIntf, output, re.S)
+        infos = {}
+        for section in sections:
+            info = self.filter_one_section(section)
+            name = info[0][0].strip()
+            infos[name] = info[1:]
+        return infos
+    ########################################################################
+    #### switch mode select
+    ########################################################################
+    def get_current_mode(self):
+        '''get current switch mode
+
+        quanta ons system has no command to show shell layer. Currently use
+        help output message to judge current shell level
+        '''
+        modes = {
+        # shell level :  prompt, help
+            "user": 'enable  Enter to the privileged mode',
+            "privileged": ('configure      '
+                           'Enter configuration mode'),
+            "configure": 'interface          Configure interfaces',
+            "port config":  
+                    ('channel-group   '
+                     'Ethernet channel group bundling configuration'),
+            "port-channel config":
+                ('lacp           '
+                 'Determines whether this LAG processes Received LACPDUs'),
+            }
+        mode = "unknown"
+        try:
+            output = self.console(["help", 'Switch'])
+            for name, value in modes.iteritems():
+                if value in output:
+                    mode = name
+                    break
+        except Exception as e:
+            print e
+        finally:
+            pass
+
+        msg = "current on {0} mode".format(mode)
+        self.logger.info(msg)
+        return mode
+
+    def enter_user(self):
+        '''enter user mode'''
+        mode = self.get_current_mode()
+        if mode == "user":
+            return
+        elif mode == "privileged":
+            cmds = ['exit', 'Switch >']
+        elif mode == "configure":
+            cmds = ["exit", "Switch #"]
+        else:
+            cmds = [["exit", "Switch \(config\)#"],
+                    ["exit", "Switch #"]]
+
+        self.console(cmds)
+
+    def enter_privileged(self):
+        '''enter privileged mode'''
+        mode = self.get_current_mode()
+        if mode == "user":
+            cmds = ["enable", "Switch #"]
+        elif mode == "privileged":
+            return
+        elif mode == "configure":
+            cmds = ["exit", "Switch #"]
+        else:
+            cmds = [["exit", "Switch \(config\)#"],
+                    ["exit", "Switch #"]]
+
+        self.console(cmds)
+
+    def enter_configure(self):
+        '''enter configure mode'''
+        mode = self.get_current_mode()
+        if mode == "user":
+            cmds = [["enable", "Switch #"],
+                    ["configure", "Switch \(config\)#"],]
+        elif mode == "privileged":
+            cmds = ["configure", "Switch \(config\)#"]
+        elif mode == "configure":
+            return
+        else:
+            cmds = ["exit", "Switch \(config\)#"]
+        self.console(cmds)
+    ########################################################################
+    #### global effective method
+    ########################################################################
+    def clear_switch_stats(self):
+        '''
+        quanta switch doesn't support clear specified port channel. When
+        multiple scenes are running, don't run this method
+        '''
+        msg = "clear switch all ports statistics data"
+        self.logger.warning(msg)
+        cmds = [['clear statistics', 'Proceed with clear operation'],
+                ['yes', '#', 2]]
+        
+        self.enter_privileged()
+        self.console(cmds)
+    ########################################################################
+    #### interface method
+    ########################################################################
+    def intf_get_config(self, ports):
+        '''get interface configuration by port name or port name list
+        '''
+        if isinstance(ports, (tuple, list)):
+            _ports = ",".join(ports)
+        elif isinstance(ports, str):
+            _ports = ports
+        else:
+            msg = "ports param are wrong"
+            raise SwitchException(msg)
+
+        cmds = ["show running-config interface {0}".format(_ports), '#']
+        
+        self.enter_privileged()
+        output = self.console(cmds)
+        configs = self.filter_interfaces_config(output)
+
+        return configs
+
+    def intf_reset_config(self, port, attrs):
+        '''reset interface configurationt to default status'''
+        cmds = ["interface {0}".format(port), '#']
+        
+        self.enter_privileged()
+        self.console(cmds)
+        
+        cmds = []
+        for attr in attrs:
+            if not attr.startswith('no '):
+                cmds.append(["no {0}".format(attr), '#'])
+            else:
+                cmds.append([attr[3:], "# "])
+        self.console(cmds)
+
+    def intf_get_vlan_attr(self, port_id):
+        '''get interface vlan ids'''
+        prompt = 'Switch #'
+        cmd = ["show running-config interface {0}".format(port_id), prompt]
+        
+        self.enter_privileged()
+        output = self.console(cmd)
+        pat = "switchport vlan add (.*) .*"
+        vlan_ids = re.findall(pat, output)
+        return vlan_ids
+
+    def intf_set_vlan_attr(self, vlan_id, port_id, scene='normal'):
+        '''remove port from previous vlan and add port to new vlan'''
+        prompt = 'Switch \(config-if {0}\)#'.format(port_id)
+        
+        if scene == 'lacp':
+            _cmds =[
+                "interface {0}".format(port_id),
+                "no switchport pvid",
+                "switchport pvid {0}".format(vlan_id),]
+        else:
+            vlans = self.intf_get_vlan_attr(port_id)
+            clear_vlan_cmd = "" if not vlans \
+                     else "no switchport vlan add {0}".format(",".join(vlans))
+            _cmds =[
+                "interface {0}".format(port_id),
+                # clear old vlan
+                "no switchport pvid",
+                clear_vlan_cmd,
+                # set vlan attribute
+                "switchport vlan add {0} untagged".format(vlan_id),
+                "switchport pvid {0}".format(vlan_id),]
+        cmds = map(lambda x: [x, prompt], _cmds)
+
+        self.enter_configure()
+        self.console(cmds)
+
+    def intf_get_pch_id(self, port_id):
+        '''get interface port channel id. 
+        
+        If not binding to any port channel, return None
+        '''
+        attrs = self.intf_get_config([port_id])
+        for attr_section in attrs.values()[0]:
+            if attr_section[0] and "channel-group" in attr_section[0]:
+                pch_attr = attr_section
+                break
+        else:
+            return None
+        pat = "channel-group (\d+) .*"
+        ch_grp_id = re.findall(pat, pch_attr[0])
+        return int(ch_grp_id[0])
+
+    def intf_unbind_pch(self, ch_grp_id, port_id):
+        '''unbind interface from port channel'''
+        prompt = 'Switch \(config-if {0}\)#'.format(port_id)
+        _cmds =[
+            "interface {0}".format(port_id),
+            "no channel-group {0}".format(ch_grp_id),]
+        cmds = map(lambda x: [x, prompt], _cmds)
+        ret_mode= [['exit', '#']]
+        
+        self.enter_configure()
+        self.console(cmds + ret_mode)
+
+    def intf_close_lldp(self, port_id):
+        '''close interface lldp transmit/receive'''
+        prompt = 'Switch \(config-if {0}\)#'.format(port_id)
+        _cmds =[
+            "interface {0}".format(port_id),
+            "no lldp receive",
+            "no lldp transmit"]
+        cmds = map(lambda x: [x, prompt], _cmds)
+        ret_mode= [['exit', '#']]
+        
+        self.enter_configure()
+        self.console(cmds + ret_mode)
+        
+    def intf_open_lldp(self, port_id):
+        '''open interface lldp transmit/receive'''
+        prompt = 'Switch \(config-if {0}\)#'.format(port_id)
+        _cmds =[
+            "interface {0}".format(port_id),
+            "lldp receive",
+            "lldp transmit"]
+        cmds = map(lambda x: [x, prompt], _cmds)
+        ret_mode= [['exit', '#']]
+        
+        self.enter_configure()
+        self.console(cmds + ret_mode)
+
+    def intf_get_brief(self, port):
+        '''get interface brief information'''
+        cmds = ['show interface {0}'.format(port), '#', 3]
+        
+        self.enter_privileged()
+        output = self.console(cmds)
+        if not output:
+            return None
+        attrs = self.filter_ports_attr(output)
+        return attrs
+
+    def intf_get_transceiver(self, port):
+        '''get interface transceiver information'''
+        cmds = ["show interface {0} transceiver".format(port), '#']
+        
+        self.enter_privileged()
+        output = self.console(cmds)
+        if not output:
+            return None
+        attrs = self.filter_ports_attr(output)
+        return attrs
+
+    def intf_shutdown(self, port_id):
+        '''set interface link down
+        
+        Quanta swith don't support set shutdown when the port is a member 
+        of port channel, it herit the port status of port channel
+        '''
+        self.enter_configure()
+        cmds = [["interface {0}".format(port_id), '#'],
+                ["shutdown", '#']]
+        self.console(cmds)
+
+    def intf_no_shutdown(self, port_id):
+        '''set interface link up
+        
+        Quanta swith don't support set shutdown when the port is a member 
+        of port channel, it herit the port status of port channel
+        '''
+        self.enter_configure()
+        cmds = [["interface {0}".format(port_id), '#'],
+                ["no shutdown", '#']]
+        self.console(cmds)
+
+    def intf_get_stats(self, port):
+        '''get interface statistics data'''
+        cmds = ['show statistics interface {0}'.format(port), '#', 5]
+        
+        self.enter_privileged()
+        output = self.console(cmds)
+        return self.filter_one_attrs(output)
+
+    def intf_clear_stats(self, port):
+        '''clear interface statistics data
+        
+        only apply on the interface not binding to any port-channel
+        '''
+        cmds = [
+        ['clear statistics {0}'.format(port), 'Proceed with clear operation'],
+        ['yes', '#', 2]]
+        
+        self.enter_privileged()
+        self.console(cmds)
+
+    ########################################################################
+    #### port channel/channel group method
+    ########################################################################
+    def create_port_channel(self, ch_grp_id):
+        '''create a new port channel'''
+        if self.pch_is_exist(ch_grp_id):
+            msg = "port channel {0} has created".format(ch_grp_id)
+            self.logger.info(msg)
+            return
+        # create a new one
+        prompt = 'Switch \(config-if\)#'
+        cmds = [['interface port-channel {0}'.format(ch_grp_id), prompt],
+                ['shutdown', prompt],
+                ['exit', '#']]
+
+        self.enter_configure()
+        self.console(cmds)
+        # check status
+        if self.pch_is_exist(ch_grp_id):
+            msg = "port channel {0} create successful".format(ch_grp_id)
+            self.logger.info(msg)
+        else:
+            msg = "port channel {0} create failed".format(ch_grp_id)
+            raise SwitchException(msg)
+
+    def pch_is_exist(self, ch_grp_id):
+        '''check if port channel has been created'''
+        cmds = ['show interface port-channel', '#']
+        
+        self.enter_privileged()
+        output = self.console(cmds)
+        infos = self.filter_pchs_attr(output)
+        name = "lag{0}".format(ch_grp_id)
+        if name in infos.keys():
+            return True
+        else:
+            return False
+
+    def pch_id_in_range(self, ch_grp_id):
+        '''check if port channel id is in the right range
+        
+        The range is set by sub class
+        '''
+        if not self.PORT_CHANNEL_RANGE:
+            msg = "PORT_CHANNEL_RANGE should be set by subclass"
+            raise SwitchException(msg)
+        
+        flag = ch_grp_id >= self.PORT_CHANNEL_RANGE[0] and \
+               ch_grp_id <= self.PORT_CHANNEL_RANGE[1]
+        return flag
+
+    def pch_set_load_balance(self, mode):
+        '''set port channel load balance
+        
+        It is a global effective status flag
+        
+        @param mode:
+            dscp            Load balancing by IP DSCP.
+            dst-ip          Load balancing by destination IP address.
+            dst-mac         Load balancing by destination MAC address.
+            ether-type      Load balancing by ethertype.
+            inner-vlan-id   Load balancing by in VLAN ID.
+            inner-vlan-pri  Load balancing by in VLAN priority.
+            ip-protocol     Load balancing by IP protocol.
+            ip6-flow        Load balancing by IPv6 traffic flow.
+            l4-dst-port     Load balancing by layer 4 destination port.
+            l4-src-port     Load balancing by layer 4 source port.
+            outer-vlan-id   Load balancing by out VLAN ID.
+            outer-vlan-pri  Load balancing by out VLAN priority.
+            src-ip          Load balancing by source IP address.
+            src-mac         Load balancing by source MAC address.
+        '''
+        supports = [
+            'dscp', 'dst-ip', 'dst-mac', 'ether-type', 'inner-vlan-id',
+            'inner-vlan-pri', 'ip-protocol', 'ip6-flow', 'l4-dst-port',
+            'l4-src-port', 'outer-vlan-id',  'outer-vlan-pri', 'src-ip',
+            'src-mac']
+        if mode not in supports:
+            msg = "load balance {0} is not supported".format(mode)
+            raise SwitchException(msg)
+
+        prompt = 'Switch \(config\)#'
+        cmds = ['port-channel load-balance {0}'.format(mode), prompt]
+        
+        self.enter_configure()
+        self.console(cmds)
+
+    def pch_remove_port(self, ch_grp_id, port):
+        '''unbind a port from port channel
+        
+        only remove port in channel group, not change other configuration
+        '''
+        ch = ch_grp_id
+        prompt = 'Switch \(config-if {0}\)#'.format(port)
+        cmds = [
+            ['interface {0}'.format(port), prompt, 2],
+            ['no channel-group {0}'.format(ch), prompt, 2],
+            ['exit', "Switch \(config\)#"],
+            ['exit', "Switch #"]]
+        
+        self.enter_configure()
+        self.console(cmds)
+
+    def pch_add_port(self, ch_grp_id, port):
+        '''bind a port to a port channel
+        
+        only add port in channel group, not change other configuration
+        '''
+        ch = ch_grp_id
+        prompt = 'Switch \(config-if {0}\)#'.format(port)
+        cmds = [
+            ['interface {0}'.format(port), prompt, 2],
+            ['channel-group {0}'.format(ch), prompt],
+            ['exit', "Switch \(config\)#"],
+            ['exit', "Switch #"]]
+        
+        self.enter_configure()
+        self.console(cmds)
+
+    def pch_remove_ports(self, ports):
+        '''unbind a list of port from any port channel'''
+        for port in ports:
+            ch = self.intf_get_pch_id(port)
+            if not ch:
+                continue
+            prompt = 'Switch \(config-if {0}\)#'.format(port)
+            cmds = [
+                ['interface {0}'.format(port), prompt, 2],
+                ['no channel-group {0}'.format(ch), prompt, 2],
+                ['exit', "Switch \(config\)#", 2]]
+            
+            self.enter_configure()
+            self.console(cmds)
+
+    def pch_get_ports_config(self, ch_grp_id):
+        '''get ports' configuration belong to a port channel
+        
+        quanta switch not support query all ports config in one command, so it
+        will be very slow here
+        '''
+        ports = self.pch_get_member(ch_grp_id)
+        members = {}
+        self.enter_privileged()
+        for port_name in ports:
+            cmds = ["show running-config interface " + port_name, '#']
+            output = self.console(cmds)
+            if output:
+                members[port_name] = output
+
+        return members
+
+    def pch_reset_port_config(self, port, attrs):
+        '''release interface from port channel'''
+        # not done here
+        return False
+        cmds = ["interface {0}".format(port), '#']
+        
+        self.enter_privileged()
+        self.console(cmds)
+        
+        cmds = []
+        for attr in attrs:
+            if not attr.startswith('no '):
+                cmds.append(["no {0}".format(attr), '#'])
+            else:
+                cmds.append([attr[3:], "# "])
+        self.console(cmds)
+
+    def pch_set_ip_igmp(self, ch_grp_id):
+        '''set port channel ip igmp'''
+        prompt = 'Switch \(config-if\)#'
+        cmds = [['interface port-channel {0}'.format(ch_grp_id), prompt],
+                ['ip igmp', prompt],
+                ['exit', '#']]
+        
+        self.enter_configure()
+        self.console(cmds)
+
+    def pch_close_ip_igmp(self, ch_grp_id):
+        '''close port channel ip igmp'''
+        prompt = 'Switch \(config-if\)#'
+        cmds = [['interface port-channel {0}'.format(ch_grp_id), prompt],
+                ['no ip igmp', prompt],
+                ['exit', '#']]
+        
+        self.enter_configure()
+        self.console(cmds)
+
+    def pch_no_shutdown(self, ch_grp_id):
+        '''set port channel on ``no shutdown`` status'''
+        prompt = 'Switch \(config-if\)#'
+        cmds = [['interface port-channel {0}'.format(ch_grp_id), prompt],
+                ['no shutdown', prompt],
+                ['ip igmp', prompt], # TBD
+                ['exit', '#']]
+        
+        self.enter_configure()
+        self.console(cmds)
+
+    def pch_shutdown(self, ch_grp_id):
+        '''set port channel on ``no shutdown`` status'''
+        prompt = 'Switch \(config-if\)#'
+        cmds = [['interface port-channel {0}'.format(ch_grp_id), prompt],
+                ['shutdown', prompt],
+                ['no ip igmp', prompt],
+                ['exit', '#']]
+        
+        self.enter_configure()
+        self.console(cmds)
+
+    def pch_get_member(self, ch_grp_id):
+        '''get port member of a port channel'''
+        details = self.pch_get_group_info(ch_grp_id)
+        members = sorted(details.keys())
+        
+        return members
+
+    def pch_get_member_status(self, ch_grp_id):
+        '''get port members' status of a port channel'''
+        members = self.pch_get_member(ch_grp_id)
+        if not members:
+            msg = "no member attached on port-channel {0}".format(ch_grp_id)
+            self.logger.error(msg)
+            return False
+
+        err_port = []
+        for name, attrs in members.iteritems():
+            if attrs['Mode'] != 'Active':
+                err_port.append(name)
+        if err_port:
+            msg = "{0} not at Active mode".format(" ".join(err_port))
+            self.logger.error(msg)
+            return False
+        else:
+            return True
+
+    def pch_get_group_info(self, ch_grp_id):
+        '''get port member status of a channel group'''
+        cmd = ["show channel-group {0}".format(ch_grp_id), "#"]
+        
+        self.enter_privileged()
+        output = self.console(cmd)
+        if "Error! Invalid interface range has been specified" in output:
+            return []
+        infos = self.filter_ports_attr(output)
+        return infos
+
+    def pch_get_grp_remote_info(self, ch_grp_id):
+        '''get all ports remote information of a channel group'''
+        cmd = ["show channel-group {0} remote".format(ch_grp_id), "#"]
+        
+        self.enter_privileged()
+        output = self.console(cmd)
+        infos = self.filter_ports_attr(output)
+        return infos
+
+    def pch_get_grp_admin_info(self, ch_grp_id):
+        '''get all ports admin information of a channel group'''
+        cmd = ["show channel-group {0} admin".format(ch_grp_id), "#"]
+        
+        self.enter_privileged()
+        output = self.console(cmd)
+        infos = self.filter_ports_attr(output)
+        return infos
+
+    def pch_get_ports_stats(self, ports):
+        '''get all ports statistics of a channel group'''
+        stats_grp = {}
+        for port_id in ports:
+            stats = self.intf_get_stats(port_id)
+            stats_grp[port_id] = stats
+        return stats_grp
+
+    def pch_clear_stats(self, ch_grp_id, ports):
+        '''clear all ports statistics data of a port channel
+        
+        quanta switch doesn't support clear specified port channel statistics.
+        An interface should unbind from a port channel before clear its 
+        statistics data
+        '''
+        for port_id in ports:
+            self.pch_remove_port(ch_grp_id, port_id)
+            self.intf_clear_stats(port_id)
+            self.pch_add_port(ch_grp_id, port_id)
+
+    ########################################################################
+    #### vlan method
+    ########################################################################
+    def create_vlan(self, vlan_id):
+        '''create a new vlan'''
+        if self.vlan_is_exist(vlan_id):
+            msg = "vlan {0} has created".format(vlan_id)
+            self.logger.info(msg)
+            return
+        # create a new one
+        cmds = [['vlan-database', 'Switch \(vlan\)#'],
+                ['vlan {0}'.format(vlan_id), 'Switch \(vlan\)#'],
+                ['exit', '#', 2]]
+        
+        self.enter_privileged()
+        self.console(cmds)
+        if self.vlan_is_exist(vlan_id):
+            msg = "vlan {0} create successful".format(vlan_id)
+            self.logger.info(msg)
+        else:
+            msg = "vlan {0} create failed".format(vlan_id)
+            raise SwitchException(msg)
+
+    def vlan_is_exist(self, vlan_id):
+        '''check if vlan has been created'''
+        cmds = ['show vlan', '#']
+        
+        self.enter_privileged()
+        output = self.console(cmds)
+        name = str(vlan_id) + "  "
+        if name in output:
+            return True
+        else:
+            return False
+
+    def vlan_id_in_range(self, vlan_id):
+        '''check if vlan id is in the right range'''
+        if not self.VLAN_RANGE:
+            msg = "VLAN_RANGE should be set by subclass"
+            raise SwitchException(msg)
+        
+        flag = vlan_id >= self.VLAN_RANGE[0] and \
+               vlan_id <= self.VLAN_RANGE[1]
+        return flag
+
+    def vlan_remove_ports(self, ports):
+        '''reset port vlan to default 1'''
+        pass
+    ########################################################################
+    #### lacp method
+    ########################################################################
+    def lacp_set_port_channel(self, vlan_id, ch_grp_id):
+        '''set a new port channel for lacp scene'''
+        prompt = 'Switch \(config-if\)#'
+        _cmds =['interface port-channel {0}'.format(ch_grp_id),
+                'no switchport vlan add 1',
+                'switchport vlan add {0} untagged'.format(vlan_id),
+                'switchport pvid {0}'.format(vlan_id),
+                'lacp',
+                'shutdown']
+        cmds = map(lambda x: [x, prompt], _cmds) + [['exit', '#']]
+        
+        self.enter_configure()
+        self.console(cmds)
+
+    def lacp_init_ports(self, vlan_id, ch_grp_id, ports):
+        '''initialize lacp configuration
+        
+        add ports into one port channel, set it on correct lacp 
+        configuration and check if port has been added successfully.
+        '''
+        # reset port configuration
+        for port in ports:
+            _ch_grp_id = self.intf_get_pch_id(port)
+            if not _ch_grp_id:
+                continue
+            if _ch_grp_id == ch_grp_id:
+                continue
+            self.intf_unbind_pch(_ch_grp_id, port)
+        # release ports bind to port channel
+        members = self.pch_get_member(ch_grp_id)
+        self.pch_remove_ports(members)
+        # add ports
+        for port in ports:
+            self.intf_set_vlan_attr(vlan_id, port, 'lacp')
+            self.pch_add_port(ch_grp_id, port)
+        # set lacp configuration
+        for port in ports:
+            self.lacp_intf_set_attr(vlan_id, ch_grp_id, port)
+        # close lldp
+        for port in ports:
+            self.intf_close_lldp(port)
+        # check if port channel members are the desired interfaces
+        members = self.pch_get_member(ch_grp_id)
+        if cmp(sorted(members), sorted(ports)) == 0:
+            msg = "add ports success"
+            self.logger.info(msg)
+        else:
+            msg = "fail to add ports"
+            self.logger.error(msg)
+            raise SwitchException(msg)
+
+    def lacp_add_ports(self, vlan, ch_grp_id, ports):
+        '''add ports to a lacp
+
+        add ports into one port channel, set it on correct lacp 
+        configuration and check if port has been added successfully.
+        '''
+        _cmds =[
+            'interface {port_id}',
+            'channel-group {ch_grp_id}',
+            'channel-group {ch_grp_id} mode passive',
+            'no channel-group {ch_grp_id} collecting',
+            'no channel-group {ch_grp_id} distributing',
+            #'channel-group {ch_grp_id} synchronization'
+            ]
+        ret_mode= [['exit', '#']]
+        # set port lacp configuration
+        for port in ports:
+            #attrs = self.intf_get_config(port)
+            #self.intf_reset_config(port, attrs)
+            attrs = {'port_id': port,
+                     'ch_grp_id': ch_grp_id,}
+            prompt = 'Switch \(config-if {0}\)#'.format(port)
+            cmds = map(lambda x: [x.format(**attrs), prompt], _cmds)
+            
+            self.enter_configure()
+            self.console(cmds + ret_mode)
+            self.intf_close_lldp(port)
+        # check lacp channel group create successfully
+        members = self.pch_get_member(ch_grp_id)
+        if cmp(sorted(members), sorted(ports)) == 0:
+            msg = "add ports success"
+            self.logger.info(msg)
+        else:
+            msg = "fail to add ports"
+            self.logger.error(msg)
+            raise SwitchException(msg)
+
+    def lacp_intf_set_attr(self, vlan_id, ch_grp_id, port_id):
+        '''set interface lacp configuration'''
+        attrs = {'port_id': port_id,
+                 'ch_grp_id': ch_grp_id,}
+        _cmds =[
+            "interface {port_id}",
+            # config actor, set port in passive status  
+            "channel-group {ch_grp_id} mode passive",
+            "channel-group {ch_grp_id} timeout long",
+            "channel-group {ch_grp_id} aggregation multiple",
+            "channel-group {ch_grp_id} lacp port-priority 128",
+            #"channel-group {ch_grp_id} key {0}",
+            "no channel-group {ch_grp_id} synchronization",
+            "channel-group {ch_grp_id} expired",
+            "no channel-group {ch_grp_id} collecting",
+            "no channel-group {ch_grp_id} defaulting",
+            "no channel-group {ch_grp_id} distributing",
+            # config parter
+            "channel-group {ch_grp_id} partner key 0",
+            "channel-group {ch_grp_id} partner number 1",
+            "channel-group {ch_grp_id} partner priority 32768",
+            "channel-group {ch_grp_id} partner system priority 8"
+            ]
+        prompt = 'Switch \(config-if {0}\)#'.format(port_id)
+        cmds = map(lambda x: [x.format(**attrs), prompt], _cmds)
+        ret_mode= [['exit', '#']]
+        
+        self.enter_configure()
+        self.console(cmds + ret_mode)
+
+    def lacp_close_ports(self, ch_grp_id, ports):
+        ret_mode= [['exit', '#']]
+        #---------------------------------------
+        # close lacp port channel
+        _cmds =[
+            'interface {port_id}',
+            'channel-group {ch_grp_id} mode passive',
+            'no channel-group {ch_grp_id} collecting',
+            'no channel-group {ch_grp_id} distributing']
+        self.enter_configure()
+        for port in sorted(ports):
+            attrs = {'port_id': port,
+                     'ch_grp_id': ch_grp_id,}
+            prompt = 'Switch \(config-if {0}\)#'.format(port)
+            cmds = map(lambda x: [x.format(**attrs), prompt], _cmds)
+            self.console(cmds + ret_mode)
+        time.sleep(5)
+
+    def lacp_set_port_ready(self, ch_grp_id, ports):
+        #---------------------------------------
+        # close lacp port channel
+        self.lacp_close_ports(ch_grp_id, ports)
+        #---------------------------------------
+        ret_mode= [['exit', '#']]
+        # reset lacp port channel
+        _cmds =[
+            'interface {port_id}',
+            #'channel-group {ch_grp_id} lacp port-priority 128',
+            "no channel-group {ch_grp_id} defaulting",
+            'channel-group {ch_grp_id} timeout long',
+            'channel-group {ch_grp_id} mode active',
+            #'channel-group {ch_grp_id} partner key 0',
+            #'channel-group {ch_grp_id} partner number 1,
+            ]
+        for port in sorted(ports):
+            attrs = {'port_id': port,
+                     'ch_grp_id': ch_grp_id,}
+            prompt = 'Switch \(config-if {0}\)#'.format(port)
+            cmds = map(lambda x: [x.format(**attrs), prompt], _cmds)
+            self.console(cmds + ret_mode)
+        # wait 5 second to make sure port ready to work  
+        time.sleep(5)
+        _cmds = ['interface {port_id}',
+            'channel-group {ch_grp_id} collecting',
+            'channel-group {ch_grp_id} distributing',
+            'channel-group {ch_grp_id} synchronization',]
+        for port in sorted(ports):
+            attrs = {'port_id': port,
+                     'ch_grp_id': ch_grp_id,}
+            prompt = 'Switch \(config-if {0}\)#'.format(port)
+            cmds = map(lambda x: [x.format(**attrs), prompt], _cmds)
+            self.console(cmds + ret_mode)
+        # wait default long timeout interval to make sure lacp sync with
+        # parter successful
+        time.sleep(30)
+
+    def lacp_get_info(self, ch_grp_id):
+        infos = self.pch_get_group_info(ch_grp_id)
+        return infos
+
+    def lacp_get_remote_info(self, ch_grp_id):
+        infos = self.pch_get_grp_remote_info(ch_grp_id)
+        return infos
+
+    def lacp_get_admin_info(self, ch_grp_id):
+        infos = self.pch_get_grp_admin_info(ch_grp_id)
+        return infos
+
+    def lacp_is_ready(self, ch_grp_id):
+        max_try = 3
+        time_interval = 10
+        while max_try:
+            details = self.lacp_get_info(ch_grp_id)
+            msgs = []
+            for port, value in details.iteritems():
+                # check if interface lacp is on enable status
+                if value['LACP Operational Status'] != 'Enabled':
+                    msg = "interface {0} lacp not ready".format(port)
+                    msgs.append(msg)
+                # check if interface is ready for traffic
+                if 'Churn Detection Status' != 'True':
+                    msg = "interface {0} traffic not ready".format(port)
+                    msgs.append(msg)
+            else:
+                return True
+            time.sleep(time_interval)
+            max_try -= 1
+        else:
+            error = os.linesep.join(msgs)
+            raise SwitchException(error)
+
+    def lacp_filter_intf_attrs(self, content, patStr):
+        pat = re.compile(patStr)
+        result = pat.findall(content)
+        if not result:
+            msg = "have not found expected content"
+            self.logger.error(msg)
+            return None
+        info = result[0]
+        attrs = {}
+        for cnt in range(1, len(info), 2):
+            attrs.update({info[cnt]: info[cnt+1]})
+        attrs.update({'id': info[0]})
+        return attrs
+    ########################################################################
+    #####    use for debug/unit test
+    ########################################################################
+    def test_debug_cmds(self):
+        self.pch_add_ports(100, 4000, ['xe1', 'xe2', 'xe3', 'xe4'])
+        self.pch_get_ports_config(4000)
+        self.pch_get_member_status(4000)
+        self.intf_get_config(["xe1"])
+        self.intf_shutdown("xe10")
+        self.intf_no_shutdown("xe10")
+
+    def test_get_current_mode(self):
+        self.enter_configure()
+        self.console(["interface xe1", "Switch"])
+        self.enter_configure()
+        self.console(["exit", "Switch"])
+        self.enter_configure()
+
+class QuantaT3048Iz1(QuantaONS):
+    '''Quanta switch T3048-Iz1'''
+    # quanta 3048H switch maximum port number
+    MAX_PORTS = 48
+    VLAN_RANGE = [1, 4094]
+    PORT_CHANNEL_RANGE = [3800, 4094]
+    def __init__(self, *args, **kwargs):
+        super(QuantaT3048Iz1, self).__init__(*args, **kwargs)
+
+class LacpSceneBase(object):
+    def __init__(self):
+        pass
+
+    def set_interface_down(self, port):
+        raise NotImplementedError
+
+    def set_interface_up(self, port):
+        raise NotImplementedError
+
+    def get_interface_stats(self):
+        raise NotImplementedError
+
+    def get_all_statistics(self):
+        raise NotImplementedError
+
+    def clear_all_statistics(self):
+        raise NotImplementedError
+
+    @abstractmethod
+    def create_scene(self):
+        '''create lacp scene'''
+        raise NotImplementedError
+
+    @abstractmethod
+    def init_scene(self):
+        '''initialize lacp scene'''
+        raise NotImplementedError
+
+    @abstractmethod
+    def start_scene(self):
+        '''start lacp scene'''
+        raise NotImplementedError
+
+    @abstractmethod
+    def reset_scene(self):
+        '''close lacp scene'''
+        raise NotImplementedError
+
+    @abstractmethod
+    def stop_scene(self):
+        '''close lacp scene'''
+        raise NotImplementedError
+
+    @abstractmethod
+    def delete_scene(self):
+        '''delete lacp scene, release all resource'''
+        raise NotImplementedError
+
+    @abstractmethod
+    def close(self):
+        raise NotImplementedError
+
+class QuantaLacpScene(LacpSceneBase):
+    '''Quanta switch lacp scene'''
+    
+    CLS ={'t3048-iz1': QuantaT3048Iz1}
+    def __init__(self, cls_name, *args, **kwargs):
+        model = kwargs.get('model')
+        if not model:
+            msg = "desired switch {0} is not supported".format(model)
+            raise SwitchException(msg)
+        self.logger = kwargs.get('logger')
+        self.logger.info("use switch <{model}>".format(**kwargs))
+        #self.sw = cls_name(*args, **kwargs)
+        self.sw = self.CLS[model](*args, **kwargs)
+    ########################################################################
+    # switch logic method for lacp
+    ########################################################################
+    def lacp_bind_ports(self, vlan, ch_grp_id, ports):
+        self.sw.lacp_add_ports(vlan, ch_grp_id, ports)
+
+    def lacp_unbind_ports(self, vlan, ch_grp_id, ports):
+        self.sw.pch_remove_ports(vlan, ch_grp_id, ports)
+
+    def lacp_get_interface_info(self, port_id):
+        '''get port status related with lacp'''
+        pass
+    ########################################################################
+    ##### switch abstract method for user
+    ########################################################################
+    def get_member(self):
+        ''' get lacp members '''
+        return self.sw.pch_get_member(self.ch_grp_id)
+
+    def get_all_statistics(self):
+        ''' get lacp members' statistics '''
+        return self.sw.pch_get_ports_stats(self.ports)
+
+    def clear_all_statistics(self):
+        '''clear lacp members' statistics
+        
+        Run it before creating lacp channel with testpmd
+        '''
+        self.sw.pch_shutdown(self.ch_grp_id)
+        self.sw.pch_clear_stats(self.ch_grp_id, self.ports)
+        #self.sw.pch_no_shutdown(self.ch_grp_id)
+        # here long time wait for port rebind to port channel
+
+    def set_ready(self):
+        ''' set lacp members on ready status '''
+        self.sw.lacp_set_port_ready(self.ch_grp_id, self.ports)
+        self.sw.lacp_is_ready(self.ch_grp_id)
+
+    def set_interface_down(self, port):
+        '''set a interface on link down'''
+        msg = "quanta switch don't support shutdown port at lacp mode"
+        self.logger.warning(msg)
+
+    def set_interface_up(self, port):
+        '''set a interface on link up'''
+        msg = "quanta switch don't support no shutdown port at lacp mode"
+        self.logger.warning(msg)
+
+    def create_scene(self, vlan_id, ch_grp_id, ports):
+        '''create lacp scene on switch'''
+        self.sw.create_vlan(vlan_id)
+        self.sw.create_port_channel(ch_grp_id)
+        self.sw.lacp_set_port_channel(vlan_id, ch_grp_id)
+        #self.sw.pch_clear_ports(ports)
+        self.sw.lacp_init_ports(vlan_id, ch_grp_id, ports)
+        self.sw.pch_no_shutdown(ch_grp_id)
+
+    def init_scene(self, auto_config=False, **kwargs):
+        '''create a desired lacp scene
+        
+        @param auto_config:
+        ``True`` create a desired lacp scene automatically
+        ``False`` use a lacp scene set by user manually
+        '''
+        # get lacp scene configuration
+        _id = kwargs.get('vlan id')
+        self.vlan_id = int(_id) if isinstance(_id, (str, unicode)) else _id
+        if not self.vlan_id or not self.sw.vlan_id_in_range(self.vlan_id):
+            msg = 'vlan id not set'
+            raise SwitchException(msg)
+        
+        _id = kwargs.get('channel group id')
+        self.ch_grp_id = int(_id) if isinstance(_id, (str, unicode)) else _id
+        if not self.ch_grp_id or not self.sw.pch_id_in_range(self.ch_grp_id):
+            msg = 'channel group id not set'
+            raise SwitchException(msg)
+        
+        self.ports = kwargs.get('port member')
+        if not self.ports:
+            msg = 'port member not set'
+            raise SwitchException(msg)
+        # create lacp scene on switch
+        if auto_config:
+            self.create_scene(self.vlan_id, self.ch_grp_id, self.ports)
+
+    def clear_scene(self):
+        '''clear lacp scene
+        
+         clear interface statistics data and LPDU Counter data
+        '''
+        self.clear_all_statistics()
+        # testpmd 802.3ad long timeout is 90 second, so wait longer than that
+        # to make sure parter/actor sync successful
+        time.sleep(120)
+
+    def start_scene(self):
+        '''start lacp scene'''
+        self.sw.pch_no_shutdown(self.ch_grp_id)
+        time.sleep(60)
+
+    def reset_scene(self):
+        '''reset lacp scene'''
+        #self.clear_all_statistics()
+        self.set_ready()
+        #self.sw.pch_shutdown(self.ch_grp_id)
+        #time.sleep(10)
+        #self.sw.pch_no_shutdown(self.ch_grp_id)
+        #time.sleep(10)
+        #self.set_ready()
+        # testpmd 802.3ad long timeout is 90 second, so wait longer than that
+        # to make sure parter/actor sync successful
+        time.sleep(120)
+
+    def stop_scene(self):
+        '''stop lacp scene'''
+        self.sw.pch_shutdown(self.ch_grp_id)
+        self.sw.lacp_close_ports(self.ch_grp_id, self.ports)
+        time.sleep(60)
+
+    def delete_scene(self):
+        '''delete lacp scene'''
+        pass
+
+class CiscoLacpScene(): pass
+
+class SwitchScene(SSHConnection):
+    '''
+    : create a switch work scene base 
+    '''
+    # define different work scene based on switch manufacturer/model
+    CLS = {'quanta lacp': [QuantaLacpScene, '# '],
+           'cisco lacp':  [CiscoLacpScene, '#']}
+    def __init__(self, *arg):
+        # get switch configuration
+        (self.name, self.switch_name, self.model, ip, user, passwd,
+         self.scene, self.vlan_id, self.port_channel_id, self.ports_list,
+         auto_config) = arg
+        name = " ".join([self.switch_name, self.scene])
+        switch_CLS = self.CLS[name][0]
+        self.default_prompt = self.CLS[name][1]
+        # initialize switch session/logger
+        self.logger = getLogger(self.name)
+        super(SwitchScene, self).__init__(ip, self.name, passwd,
+                                            user, node_type="switch")
+        super(SwitchScene, self).init_log(self.logger)
+        # initialize switch equipment
+        self.say("initialize")
+        configs = {"console": self.console,
+                   "model": self.model,
+                   'logger': self.logger}
+        self.switch = switch_CLS(self.switch_name, *[], **configs)
+        lacp_scene = {'vlan id': self.vlan_id,
+                      'channel group id': self.port_channel_id,
+                      'port member': self.ports_list}
+        self.switch.init_scene(auto_config=auto_config, **lacp_scene)
+
+    def say(self, action):
+        msg_fmt = "{0} <{1}> [{2} {3}] '{4}' work scene".format
+        self.logger.info(msg_fmt(action, self.name, self.switch_name,
+                                 self.model, self.scene))
+    ########################################################################
+    ##### console method used to run switch command
+    ########################################################################
+    def check_disired_msg(self, output, expected_items):
+        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:
+            msg = "unexpected '{0}' is not in output".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 SwitchException(msg)
+
+    def console(self, cmds):
+        if len(cmds) == 0:
+            return
+        # check if cmds is string
+        if isinstance(cmds, str):
+            timeout = 15
+            cmds = [[cmds, '', timeout]]
+        # check if cmds is only one command
+        if not isinstance(cmds[0], list):
+            cmds = [cmds]
+        output_list = []
+        for item in cmds:
+            cmd = item[0]
+            expected_items = item[1]
+            if expected_items and isinstance(expected_items, (list, tuple)):
+                check_output = True
+                expected_str = expected_items[0] or self.default_prompt
+            else:
+                check_output = False
+                expected_str = expected_items or self.default_prompt
+            #----------------
+            timeout = int(item[2]) if len(item) == 3 else 5
+            #----------------
+            # run command on session
+            try:
+                output = self.send_expect(cmd, expected_str, timeout)
+                output = self.session.get_output_all() \
+                                if not output.strip() else output
+            except TimeoutException:
+                # quanta switch software don't display all output when output 
+                # is more than one pagepage, so use space charater to show the 
+                # left content
+                if self.switch_name == 'quanta':
+                    output_1 = self.session.get_output_all()
+                    try:
+                        if "<?> - help" in output_1:
+                            output_1 ='\r\n'.join(output_1.splitlines()[:-1])+\
+                                      '\r\n'
+                            output_2 = self.send_expect(" ", expected_str, 
+                                                        timeout)
+                            output = output_1 + output_2
+                    except Exception as e:
+                        output = output_1
+                    finally:
+                        pass
+                else:
+                    msg = "execute '{0}' timeout".format(cmd)
+                    raise TimeoutException(cmd, msg)
+            except Exception as e:
+                exc_info = sys.exc_info()
+                traceback.print_exception(exc_info[0], exc_info[1],
+                                          exc_info[2], None, sys.stderr)
+            finally:
+                pass
+            # when user set expected string, check it on output
+            if check_output and len(expected_items) >= 2:
+                self.check_disired_msg(output, expected_items)
+            else:
+                output_list.append(output)
+        time.sleep(2)
+        retOutput = output_list[0] if len(cmds) == 1 else output_list
+        return retOutput
+    ########################################################################
+    ##### methods for dts framework
+    ########################################################################
+    def get_ports(self):
+        """  get switch ports """
+        plist = list()
+        if self.session is None:
+            msg = "switch session failed to create"
+            self.logger.warning(msg)
+            return plist
+        for port in self.ports_list:
+            plist.append({'type': 'switch', 
+                          'pci': 'SWITCH:{0}'.format(port)})
+        return plist
+    ########################################################################
+    ##### switch methods for user
+    ########################################################################
+    def _get_mac(self, port):
+        return self.switch.get_mac(port)
+
+    def vlan(self):
+        """ return lacp scene vlan id """
+        return self.vlan_id
+
+    def port_channel(self):
+        """ return lacp scene port channel id """
+        return self.port_channel_id
+
+    def ports(self):
+        """ return lacp scene ports """
+        return self.ports_list
+
+    def get_stats(self):
+        ''' get lacp members' statistics '''
+        results = self.switch.get_all_statistics()
+        return results
+
+    def clear_stats(self):
+        ''' clear lacp members' statistics '''
+        self.switch.clear_all_statistics()
+
+    def set_intf_down(self, port_id):
+        ''' set interface down '''
+        self.switch.set_interface_down(port_id)
+
+    def set_intf_up(self, port_id):
+        ''' set interface up '''
+        self.switch.set_interface_up(port_id)
+
+    def get_member(self):
+        ''' get interfaces belong a  lacp configuration '''
+        return self.switch.get_member()
+
+    def clear(self):
+        '''clear switch work scene'''
+        self.say('start')
+        self.switch.clear_scene()
+
+    def start(self):
+        '''activate switch work scene'''
+        self.say('start')
+        self.switch.start_scene()
+
+    def reset(self):
+        '''reset switch work scene to original status'''
+        self.say('reset')
+        self.switch.reset_scene()
+
+    def stop(self):
+        '''stop switch work scene'''
+        self.say('stop')
+        self.switch.stop_scene()
+
+    def quit(self):
+        '''quit switch work scene'''
+        self.say('quit')
+        self.switch.stop_scene()
+        self.close(force=True)
+
+class Switch(object):
+    '''use for switch work scene creation
+
+    support multiple work scenes creation, every work scene configuration
+    is in dts/conf/switch.cfg. Each ``SwitchScene`` class instance manage
+    its own resources/status of work scene.
+    '''
+    def __init__(self):
+        self.switch_grp = {}
+
+    def init_scenes(self, tester):
+        for name, config in self.get_config(tester):
+            self.switch_grp[name] = SwitchScene(*config)
+
+    def get_config(self, tester):
+        '''get switch configuration from cfg file'''
+        switchRef = tester.get_switch_crb()
+        switchcfg = SwitchConf()
+        switchConfigs = switchcfg.load_switch_config()
+        if not switchRef or not switchConfigs:
+            msg = "wrong switch configuration"
+            raise ConfigParseException(msg)
+
+        for name, switch_config in switchConfigs.iteritems():
+            # under default status, switch scene will config resources status
+            # automatically
+            if 'auto_config' not in switch_config:
+                auto_config = True
+            else:
+                value = switch_config['auto_config'].lower()
+                auto_config = True if value == 'true' else False
+            config = [name,
+                # 'manufacturer' 
+                switch_config["manufacturer"],
+                # 'model'
+                switch_config["model"],
+                # switch ip address/user/passwd
+                # 'ip': 
+                switch_config["ip"],
+                # 'user': 
+                switch_config["user"],
+                # 'passwd': 
+                switch_config["passwd"],
+                # configuration scene
+                # 'scene': 
+                switch_config["scene"], 
+                # 'vlan_id': 
+                switch_config["vlan"],
+                # 'port_channel_id': 
+                switch_config["port-channel"],
+                # 'ports': 
+                switch_config["ports"],
+                auto_config]
+
+            yield name, config
\ No newline at end of file
-- 
1.9.3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [dts] [PATCH V1 4/6] pmd_bonded_8023ad: dts configuration files
  2018-06-06  5:38 [dts] [PATCH V1 0/6] pmd_bonded_8023ad: upload test plan yufengx.mo
                   ` (2 preceding siblings ...)
  2018-06-06  5:38 ` [dts] [PATCH V1 3/6] pmd_bonded_8023ad: add switch module in dts/framework yufengx.mo
@ 2018-06-06  5:38 ` yufengx.mo
  2018-06-06  5:38 ` [dts] [PATCH V1 5/6] pmd_bonded_8023ad: framework work flow yufengx.mo
  2018-06-06  5:38 ` [dts] [PATCH V1 6/6] pmd_bonded_8023ad: framework etgen/ixia yufengx.mo
  5 siblings, 0 replies; 9+ messages in thread
From: yufengx.mo @ 2018-06-06  5:38 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

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


add dts configuration support for switch equipment

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 conf/crbs.cfg       |  2 ++
 conf/ports.cfg      |  2 ++
 conf/switch.cfg     | 27 ++++++++++++++++++++++++
 framework/config.py | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 90 insertions(+), 2 deletions(-)
 create mode 100644 conf/switch.cfg

diff --git a/conf/crbs.cfg b/conf/crbs.cfg
index 0a17c35..9307d48 100644
--- a/conf/crbs.cfg
+++ b/conf/crbs.cfg
@@ -7,6 +7,7 @@
 #  tester_ip: Tester ip address
 #  tester_passwd: Tester password
 #  ixia_group: IXIA group name
+#  switch_group: switch group name
 #  channels: Board channel number
 #  bypass_core0: Whether by pass core0
 [DUT IP1]
@@ -27,5 +28,6 @@ os=linux
 tester_ip=yyy.yyy.yyy.yyy
 tester_passwd=
 ixia_group=
+switch_group=
 channels=4
 bypass_core0=True
diff --git a/conf/ports.cfg b/conf/ports.cfg
index 7fa7aae..97157c4 100644
--- a/conf/ports.cfg
+++ b/conf/ports.cfg
@@ -4,6 +4,7 @@
 #     pci=Pci BDF,intf=Kernel interface;
 #     pci=Pci BDF,mac=Mac address,peer=Tester Pci BDF,numa=Port Numa 
 #     pci=Pci BDF,peer=IXIA:card.port
+#     pci=Pci BDF,peer=SWITCH:port
 #     pci=Pci BDF,peer=Tester Pci BDF,tp_ip=$(IP),tp_path=$({PERL_PATH);
 #     pci=Pci BDF,peer=Tester Pci BDF,sec_port=yes,first_port=Pci BDF;
 # [VM NAME] virtual machine name; This section is for virutal scenario
@@ -14,6 +15,7 @@ ports =
     pci=XX:XX.X,intf=eth0;
     pci=YY:YY.Y,mac=XX:XX:XX:XX:XX:XX,peer=ZZ:ZZ.Z,numa=0;
     pci=ZZ:ZZ.Y,peer=IXIA:X.Y;
+    pci=ZZ:ZZ.Y,peer=SWITCH:XXY;
     pci=0000:XX:XX.X,peer=0000:ZZ:ZZ.Z,tp_ip=127.0.0.1,tp_path=/home/libertyTrailTP_322291/perl;
     pci=0000:YY:YY.Y,peer=0000:ZZ:ZZ.Z,sec_port=yes,first_port=XX:XX.X;
 [VM NAME]
diff --git a/conf/switch.cfg b/conf/switch.cfg
new file mode 100644
index 0000000..aa3de22
--- /dev/null
+++ b/conf/switch.cfg
@@ -0,0 +1,27 @@
+# switch port Configuration
+# switch_Group1:    a name of switch work scence
+# manufacture:      switch manufacture
+# model:            switch device model
+# ip:               switch device IP address
+# user:             switch device user name
+# passwd:           switch device user password
+# auto_config:      switch auto config resources(True or False)
+# scene:            switch work scene
+# vlan:             switch vlan id
+# port-channel:     port-channel id
+# ports:            [switch port list]
+[switch_Group1]
+manufacturer=xxxxxx
+model=xxxxxx
+ip=xxx.xxx.xxx.xxx
+user=xxxx
+passwd=xxxx
+auto_config=xxxx
+scene=xxxx
+vlan=xxx
+port-channel=xxxx
+ports=
+    xxx;
+    xxx;
+    xxx;
+    xxx;
diff --git a/framework/config.py b/framework/config.py
index 71b1c37..749e979 100644
--- a/framework/config.py
+++ b/framework/config.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,7 @@ import ConfigParser  # config parse module
 import argparse      # prase arguments module
 from settings import IXIA, CONFIG_ROOT_PATH, SUITE_SECTION_NAME
 from settings import load_global_setting, DTS_CFG_FOLDER
+from settings import SWITCH
 from exception import ConfigParseException, VirtConfigParseException, PortConfigParseException
 
 PORTCONF = "%s/ports.cfg" % CONFIG_ROOT_PATH
@@ -45,7 +46,7 @@ CRBCONF = "%s/crbs.cfg" % CONFIG_ROOT_PATH
 VIRTCONF = "%s/virt_global.cfg" % CONFIG_ROOT_PATH
 IXIACONF = "%s/ixia.cfg" % CONFIG_ROOT_PATH
 GLOBALCONF = "%s/global_suite.cfg" % CONFIG_ROOT_PATH
-
+SWITCHCONF = "%s/switch.cfg" % CONFIG_ROOT_PATH
 
 class UserConf():
 
@@ -249,6 +250,7 @@ class CrbsConf(UserConf):
     DEF_CRB = {'IP': '', 'board': 'default', 'user': '',
                'pass': '', 'tester IP': '', 'tester pass': '',
                IXIA: None, 'memory channels': 4,
+               SWITCH: None,
                'bypass core0': True}
 
     def __init__(self, crbs_conf=CRBCONF):
@@ -292,6 +294,11 @@ class CrbsConf(UserConf):
                     if value.lower() == 'none':
                         value = None
                     crb[IXIA] = value
+                elif key == 'switch_group':
+                    # None type will be check later
+                    if value.lower() == 'none':
+                        value = None
+                    crb[SWITCH] = value
                 elif key == 'channels':
                     crb['memory channels'] = int(value)
                 elif key == 'bypass_core0':
@@ -364,6 +371,56 @@ class IxiaConf(UserConf):
 
         return self.ixia_cfg
 
+
+class SwitchConf(UserConf):
+
+    def __init__(self, switch_conf=SWITCHCONF):
+        self.config_file = switch_conf
+        self.switch_cfg = {}
+        try:
+            self.switch_conf = UserConf(self.config_file)
+        except ConfigParseException:
+            self.switch_conf = None
+            raise ConfigParseException
+
+    def load_switch_config(self):
+        port_reg = r'(\S+)'
+        groups = self.switch_conf.get_sections()
+        if not groups:
+            return self.switch_cfg
+
+        keywords = ['manufacturer', 'model', 'ip', 'user', 'passwd', 'scene',
+                    'vlan', 'port-channel', 'ports', 'auto_config']
+        required_keywords = ['manufacturer', 'model', 'ip', 'user', 'passwd']
+        for group in groups:
+            switch_group = {}
+            switch_confs = self.switch_conf.load_section(group)
+            if not switch_confs:
+                continue
+            # convert file configuration to dts switchcfg
+            for conf in switch_confs:
+                _key, value = conf
+                key = _key.lower()
+                if key == 'ports':
+                    ports = self.switch_conf.load_config(value)
+                    switch_ports = []
+                    for port in ports:
+                        m = re.findall(port_reg, port)
+                        switch_ports += [port.strip() for port in m]
+                    switch_group['ports'] = switch_ports
+                elif key in keywords:
+                    switch_group[key] = value
+
+            msg_fmt = 'switch configuration file request {0} option!!!'.format
+            for i in required_keywords:
+                if i not in switch_group:
+                    print msg_fmt(i)
+
+            self.switch_cfg[group] = switch_group
+
+        return self.switch_cfg
+
+
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(
         description="Load DTS configuration files")
-- 
1.9.3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [dts] [PATCH V1 5/6] pmd_bonded_8023ad: framework work flow
  2018-06-06  5:38 [dts] [PATCH V1 0/6] pmd_bonded_8023ad: upload test plan yufengx.mo
                   ` (3 preceding siblings ...)
  2018-06-06  5:38 ` [dts] [PATCH V1 4/6] pmd_bonded_8023ad: dts configuration files yufengx.mo
@ 2018-06-06  5:38 ` yufengx.mo
  2018-06-06  5:38 ` [dts] [PATCH V1 6/6] pmd_bonded_8023ad: framework etgen/ixia yufengx.mo
  5 siblings, 0 replies; 9+ messages in thread
From: yufengx.mo @ 2018-06-06  5:38 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

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


add dts work flow support for switch equipment.

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 framework/dts.py            | 20 +++++++++++++++++++-
 framework/dut.py            | 14 +++++++++++---
 framework/exception.py      | 10 ++++++++++
 framework/logger.py         | 24 +++++++++++++++++++++++-
 framework/project_dpdk.py   |  6 +++++-
 framework/settings.py       |  7 ++++++-
 framework/ssh_connection.py |  9 ++++++---
 framework/ssh_pexpect.py    | 36 ++++++++++++++++++++++++++++++++++--
 8 files changed, 114 insertions(+), 12 deletions(-)

diff --git a/framework/dts.py b/framework/dts.py
index 0b2240c..06e2441 100644
--- a/framework/dts.py
+++ b/framework/dts.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -249,6 +249,14 @@ def dts_log_testsuite(duts, tester, suite_obj, log_handler, test_classname):
     except Exception as ex:
         pass
 
+    # check if dts use switch equipment
+    try:
+        if tester.it_uses_switch():
+            switch_scenes = getattr(tester, 'switch_scenes')
+            for name, obj in switch_scenes.iteritems():
+                obj.logger.config_suite(test_classname, obj.name)
+    except Exception as ex:
+        pass
 
 def dts_log_execution(duts, tester, log_handler):
     """
@@ -266,6 +274,15 @@ def dts_log_execution(duts, tester, log_handler):
             tester.ixia_packet_gen.logger.config_execution('ixia')
     except Exception as ex:
         pass
+    
+    # check if dts use switch equipment
+    try:
+        if tester.it_uses_switch():
+            switch_scenes = getattr(tester, 'switch_scenes')
+            for name, obj in switch_scenes.iteritems():
+                obj.logger.config_execution(obj.name)
+    except Exception as ex:
+        pass
 
 
 def dts_crbs_init(crbInsts, skip_setup, read_cache, project, base_dir, serializer, virttype):
@@ -296,6 +313,7 @@ def dts_crbs_init(crbInsts, skip_setup, read_cache, project, base_dir, serialize
     show_speedup_options_messages(read_cache, skip_setup)
     tester.set_speedup_options(read_cache, skip_setup)
     tester.init_ext_gen()
+    tester.init_switch()
 
     nic = settings.load_global_setting(settings.HOST_NIC_SETTING)
     for dutobj in duts:
diff --git a/framework/dut.py b/framework/dut.py
index 18f0b39..e230450 100644
--- a/framework/dut.py
+++ b/framework/dut.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -980,13 +980,21 @@ class Dut(Crb):
 
     def disable_tester_ipv6(self):
         for tester_port in self.ports_map:
-            if self.tester.ports_info[tester_port]['type'] != 'ixia':
+            if self.tester.ports_info[tester_port]['type'] == 'ixia':
+                continue
+            elif self.tester.ports_info[tester_port]['type'] == 'switch':
+                continue
+            else:
                 port = self.tester.ports_info[tester_port]['port']
                 port.disable_ipv6()
 
     def enable_tester_ipv6(self):
         for tester_port in range(len(self.tester.ports_info)):
-            if self.tester.ports_info[tester_port]['type'] != 'ixia':
+            if self.tester.ports_info[tester_port]['type'] == 'ixia':
+                continue
+            elif self.tester.ports_info[tester_port]['type'] == 'switch':
+                continue
+            else:
                 port = self.tester.ports_info[tester_port]['port']
                 port.enable_ipv6()
 
diff --git a/framework/exception.py b/framework/exception.py
index 654e420..027568a 100644
--- a/framework/exception.py
+++ b/framework/exception.py
@@ -143,3 +143,13 @@ class VirtVmOperationException(Exception):
 
 class VirtHostPrepareException(Exception):
     pass
+
+class SwitchException(Exception):
+    """
+    switch exception
+    """
+    def __init__(self, msg):
+        self.msg = msg
+
+    def __str__(self):
+        return "Switch exception: " + self.msg
diff --git a/framework/logger.py b/framework/logger.py
index 8d0e5e8..cd16ac1 100644
--- a/framework/logger.py
+++ b/framework/logger.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -64,6 +64,9 @@ logging.DTS_IXIA_OUTPUT = logging.DEBUG + 5
 logging.DTS_VIRTDUT_CMD = logging.INFO + 6
 logging.DTS_VIRTDUT_OUTPUT = logging.DEBUG + 6
 
+logging.DTS_SWITCH_CMD = logging.INFO + 7
+logging.DTS_SWITCH_OUTPUT = logging.DEBUG + 7
+
 logging.addLevelName(logging.DTS_DUT_CMD, 'DTS_DUT_CMD')
 logging.addLevelName(logging.DTS_DUT_OUTPUT, 'DTS_DUT_OUTPUT')
 logging.addLevelName(logging.DTS_DUT_RESULT, 'DTS_DUT_RESULT')
@@ -75,6 +78,9 @@ logging.addLevelName(logging.DTS_TESTER_RESULT, 'DTS_TESTER_RESULT')
 logging.addLevelName(logging.DTS_IXIA_CMD, 'DTS_IXIA_CMD')
 logging.addLevelName(logging.DTS_IXIA_OUTPUT, 'DTS_IXIA_OUTPUT')
 
+logging.addLevelName(logging.DTS_SWITCH_CMD, 'DTS_SWITCH_CMD')
+logging.addLevelName(logging.DTS_SWITCH_OUTPUT, 'DTS_SWITCH_OUTPUT')
+
 logging.addLevelName(logging.DTS_VIRTDUT_CMD, 'VIRTDUT_CMD')
 logging.addLevelName(logging.DTS_VIRTDUT_OUTPUT, 'VIRTDUT_OUTPUT')
 
@@ -143,6 +149,12 @@ class BaseLoggerAdapter(logging.LoggerAdapter):
     def dts_ixia_output(self, msg, *args, **kwargs):
         self.log(logging.DTS_IXIA_OUTPUT, msg, *args, **kwargs)
 
+    def dts_switch_cmd(self, msg, *args, **kwargs):
+        self.log(logging.DTS_SWITCH_CMD, msg, *args, **kwargs)
+
+    def dts_switch_output(self, msg, *args, **kwargs):
+        self.log(logging.DTS_SWITCH_OUTPUT, msg, *args, **kwargs)
+
     def dts_virtdut_cmd(self, msg, *args, **kwargs):
         self.log(logging.DTS_VIRTDUT_CMD, msg, *args, **kwargs)
 
@@ -167,6 +179,8 @@ class ColorHandler(logging.StreamHandler):
         logging.SUITE_TESTER_CMD: '',  # SYSTEM
         logging.DTS_IXIA_CMD: '',  # SYSTEM
         logging.DTS_IXIA_OUTPUT: '',  # SYSTEM
+        logging.DTS_SWITCH_CMD: '',  # SYSTEM
+        logging.DTS_SWITCH_OUTPUT: '',  # SYSTEM
         logging.DTS_VIRTDUT_CMD: '',  # SYSTEM
         logging.DTS_VIRTDUT_OUTPUT: '',  # SYSTEM
         logging.WARN: '\033[01;33m',  # BOLD YELLOW
@@ -310,6 +324,11 @@ class DTSLOG(BaseLoggerAdapter):
         elif crb.startswith('ixia'):
             self.info_lvl = logging.DTS_IXIA_CMD
             self.debug_lvl = logging.DTS_IXIA_OUTPUT
+        elif crb.startswith('switch'):
+            self.info_lvl = logging.DTS_SWITCH_CMD
+            self.debug_lvl = logging.DTS_SWITCH_OUTPUT
+
+            set_salt(crb, 'switch')
         elif crb.startswith('virtdut'):
             self.info_lvl = logging.DTS_VIRTDUT_CMD
             self.debug_lvl = logging.DTS_VIRTDUT_OUTPUT
@@ -342,6 +361,9 @@ class DTSLOG(BaseLoggerAdapter):
         elif crb == 'ixia':
             self.info_lvl = logging.DTS_IXIA_CMD
             self.debug_lvl = logging.DTS_IXIA_OUTPUT
+        elif crb == 'switch':
+            self.info_lvl = logging.DTS_SWITCH_CMD
+            self.debug_lvl = logging.DTS_SWITCH_OUTPUT
         elif crb == 'virtdut':
             self.info_lvl = logging.DTS_VIRTDUT_CMD
             self.debug_lvl = logging.DTS_VIRTDUT_OUTPUT
diff --git a/framework/project_dpdk.py b/framework/project_dpdk.py
index f87fd13..315d673 100644
--- a/framework/project_dpdk.py
+++ b/framework/project_dpdk.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,7 @@ from dut import Dut
 from tester import Tester
 from logger import getLogger
 from settings import IXIA, DRIVERS
+from settings import SWITCH
 
 
 class DPDKdut(Dut):
@@ -493,6 +494,9 @@ class DPDKtester(Tester):
                 assert ("No such file or directory" not in out), "Can not find /root/igb_uio.ko for performance"
                 self.setup_memory()
 
+        if SWITCH in self.crb and self.crb[SWITCH] is not None:
+            self.logger.info("Use switch")
+
         self.stage = "post-init"
 
     def setup_memory(self, hugepages=-1):
diff --git a/framework/settings.py b/framework/settings.py
index 07c3ac6..d1b26d9 100644
--- a/framework/settings.py
+++ b/framework/settings.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -194,6 +194,11 @@ Global macro for dts.
 IXIA = "ixia"
 
 """
+Global macro for dts.
+"""
+SWITCH = "switch"
+
+"""
 The log name seperater.
 """
 LOG_NAME_SEP = '.'
diff --git a/framework/ssh_connection.py b/framework/ssh_connection.py
index 622ed50..a849a2b 100644
--- a/framework/ssh_connection.py
+++ b/framework/ssh_connection.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -44,8 +44,11 @@ class SSHConnection(object):
     Implement send_expect/copy function upper SSHPexpet module.
     """
 
-    def __init__(self, host, session_name, username, password='', dut_id=0):
-        self.session = SSHPexpect(host, username, password, dut_id)
+    def __init__(self, host, session_name, username, password='', dut_id=0,
+                 node_type=None):
+        node_type = node_type or "normal"
+        self.session = SSHPexpect(host, username, password, dut_id,
+                                   node_type=node_type)
         self.name = session_name
         connection = {}
         connection[self.name] = self.session
diff --git a/framework/ssh_pexpect.py b/framework/ssh_pexpect.py
index 3c988b7..d266519 100644
--- a/framework/ssh_pexpect.py
+++ b/framework/ssh_pexpect.py
@@ -14,7 +14,7 @@ Aslo support transfer files to tester or DUT.
 
 class SSHPexpect(object):
 
-    def __init__(self, host, username, password, dut_id):
+    def __init__(self, host, username, password, dut_id, node_type="normal"):
         self.magic_prompt = "MAGIC PROMPT"
         self.logger = None
 
@@ -22,7 +22,39 @@ class SSHPexpect(object):
         self.username = username
         self.password = password
 
-        self._connect_host(dut_id=dut_id)
+        if node_type == "switch":
+            self.login_switch()
+        else:
+            self._connect_host(dut_id=dut_id)
+
+    def login_switch(self):
+        try:
+            self.session = pxssh.pxssh()
+            if ':' in self.host:
+                self.ip = self.host.split(':')[0]
+                self.port = int(self.host.split(':')[1])
+                self.session.login(self.ip, 
+                                   self.username,
+                                   self.password, 
+                                   #original_prompt='[$#>]',
+                                   auto_prompt_reset=False,
+                                   port=self.port, 
+                                   login_timeout=60)
+            else:
+                self.session.login(self.host, 
+                                   self.username,
+                                   self.password, 
+                                   #original_prompt=r'[$#>]',
+                                   auto_prompt_reset=False,
+                                   login_timeout=60)
+        except Exception, e:
+            print RED(e)
+            if getattr(self, 'port', None):
+                suggestion = "\nSuggession: Check if the fireware on [ %s ] " % \
+                    self.ip + "is stoped\n"
+                print GREEN(suggestion)
+
+            raise SSHConnectionException(self.host)
 
     @parallel_lock(num=8)
     def _connect_host(self, dut_id=0):
-- 
1.9.3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [dts] [PATCH V1 6/6] pmd_bonded_8023ad: framework etgen/ixia
  2018-06-06  5:38 [dts] [PATCH V1 0/6] pmd_bonded_8023ad: upload test plan yufengx.mo
                   ` (4 preceding siblings ...)
  2018-06-06  5:38 ` [dts] [PATCH V1 5/6] pmd_bonded_8023ad: framework work flow yufengx.mo
@ 2018-06-06  5:38 ` yufengx.mo
  5 siblings, 0 replies; 9+ messages in thread
From: yufengx.mo @ 2018-06-06  5:38 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

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


extend ixia class to support continuous sending stream, app will stop it after
app complete sample statistics data.

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 framework/etgen.py  | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 framework/tester.py | 115 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 238 insertions(+), 2 deletions(-)
 mode change 100755 => 100644 framework/tester.py

diff --git a/framework/etgen.py b/framework/etgen.py
index 2856a28..96acf79 100644
--- a/framework/etgen.py
+++ b/framework/etgen.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -168,6 +168,8 @@ class IxiaPacketGenerator(SSHConnection):
     """
 
     def __init__(self, tester):
+        self.bpsRate, self.oversize, self.rate = 0, 0, 0
+        self.rxPortlist, self.txPortlist = None, None
         self.tester = tester
         self.NAME = 'ixia'
         self.logger = getLogger(self.NAME)
@@ -442,6 +444,14 @@ class IxiaPacketGenerator(SSHConnection):
         self.send_expect("ixLogout", "%")
         self.send_expect("ixDisconnectTclServer %s" % self.tclServerIP, "%")
 
+    def clean_ownership(self):
+        self.send_expect("ixClearOwnership [list %s]" % string.join(
+            ['[list %d %d %d]' % (self.chasId, item['card'], item['port']) \
+                                    for item in self.ports], ' '), "% ", 10)
+        self.send_expect("ixTakeOwnership [list %s] force" % string.join(
+            ['[list %d %d %d]' % (self.chasId, item['card'], item['port']) \
+                                    for item in self.ports], ' '), "% ", 10)
+
     def config_port(self, pList):
         """
         Configure ports and make them ready for performance validation.
@@ -527,6 +537,43 @@ class IxiaPacketGenerator(SSHConnection):
 
         return {'card': int(m.group(1)), 'port': int(m.group(2))}
 
+    def get_port_stats(self, rxPortlist, txPortlist, delay=5):
+        """
+        Get RX/TX packet statistics and calculate loss rate.
+        """
+        time.sleep(delay)
+
+        #self.send_expect("ixStopTransmit portList", "%", 10)
+        time.sleep(2)
+        sendNumber = 0
+        for port in txPortlist:
+            self.stat_get_stat_all_stats(port)
+            sendNumber += self.get_frames_sent()
+            time.sleep(0.5)
+
+        self.logger.info("send :%f" % sendNumber)
+
+        assert sendNumber != 0
+
+        revNumber = 0
+        for port in rxPortlist:
+            self.stat_get_stat_all_stats(port)
+            revNumber += self.get_frames_received()
+        self.logger.info("rev  :%f" % revNumber)
+
+        return sendNumber, revNumber
+
+    def port_stats(self, portList, ratePercent, delay=5):
+        rxPortlist, txPortlist = self.rxPortlist, self.txPortlist
+        return self.get_port_stats(rxPortlist, txPortlist, delay)
+    
+    def port_line_rate(self):
+        chasId = '1'
+        port_line_rate = []
+        for port in self.ports:
+            port_line_rate.append(self.get_line_rate(chasId, port))
+        return port_line_rate
+
     def loss(self, portList, ratePercent, delay=5):
         """
         Run loss performance test and return loss rate.
@@ -560,6 +607,39 @@ class IxiaPacketGenerator(SSHConnection):
 
         return float(sendNumber - revNumber) / sendNumber, sendNumber, revNumber
 
+    def loop_latency(self, portList, ratePercent, delay=5):
+        """
+        Run latency performance test and return latency statistics.
+        """
+        rxPortlist, txPortlist = self._configure_everything(portList, ratePercent, True)
+        self.rxPortlist, self.txPortlist = rxPortlist, txPortlist
+        return True
+
+    def stop_latency(self, portList, ratePercent, delay=5):
+        """
+        Run latency performance test and return latency statistics.
+        """
+        return self.loop_get_packet_latency(self.rxPortlist)
+
+    def loop_get_packet_latency(self, rxPortlist):
+        """
+        Stop IXIA transmit and return latency statistics.
+        """
+        latencyList = []
+        time.sleep(10)
+
+        self.send_expect("ixStopTransmit portList", "%", 10)
+        for rx_port in rxPortlist:
+            self.pktGroup_get_stat_all_stats(rx_port)
+            latency = {"port": rx_port,
+                       "stdDeviation": self.get_standard_deviation(),
+                       "avgDeviation": self.get_average_deviation(),
+                       "min": self.get_min_latency(),
+                       "max": self.get_max_latency(),
+                       "average": self.get_average_latency()}
+            latencyList.append(latency)
+        return latencyList
+
     def latency(self, portList, ratePercent, delay=5):
         """
         Run latency performance test and return latency statistics.
@@ -589,6 +669,21 @@ class IxiaPacketGenerator(SSHConnection):
         """
         rxPortlist, txPortlist = self._configure_everything(port_list, rate_percent)
         return self.get_transmission_results(rxPortlist, txPortlist, delay)
+    
+    def loop_throughput(self, port_list, rate_percent=100, delay=5):
+        """
+        Run throughput performance test and return throughput statistics.
+        """
+        rxPortlist, txPortlist = self._configure_everything(port_list, rate_percent)
+        self.rxPortlist, self.txPortlist = rxPortlist, txPortlist
+        return True
+
+    def stop_loop_throughput(self, port_list, rate_percent=100, delay=5):
+        """
+        Run throughput performance test and return throughput statistics.
+        """
+        
+        return self.stop_loop_transmission(self.rxPortlist, self.txPortlist, delay)
 
     """
     This function could be used to check the packets' order whether same as the receive sequence.
@@ -686,6 +781,34 @@ class IxiaPacketGenerator(SSHConnection):
     def hook_transmission_func(self):
         pass
 
+    def loop_get_transmission_results(self, rx_port_list, tx_port_list, delay=5):
+        """
+        Override this method if you want to change the way of getting results
+        back from IXIA.
+        """
+        time.sleep(delay)
+        bpsRate = self.bpsRate
+        rate = self.rate
+        oversize = self.oversize
+        for port in rx_port_list:
+            self.stat_get_rate_stat_all_stats(port)
+            out = self.send_expect("stat cget -framesReceived", '%', 10)
+            rate += int(out.strip())
+            out = self.send_expect("stat cget -bitsReceived", '% ', 10)
+            self.logger.debug("port %d bits rate:" % (port) + out)
+            bpsRate += int(out.strip())
+            out = self.send_expect("stat cget -oversize", '%', 10)
+            oversize += int(out.strip())
+
+        self.logger.info("Rate: %f Mpps" % (rate * 1.0 / 1000000))
+        self.logger.info("Mbps rate: %f Mbps" % (bpsRate * 1.0 / 1000000))
+        self.hook_transmissoin_func()
+
+        return True
+
+    def stop_loop_transmission(self, rx_port_list, tx_port_list, delay=5):
+        return self.get_transmission_results(self.rxPortlist, self.txPortlist, delay)
+
     def get_transmission_results(self, rx_port_list, tx_port_list, delay=5):
         """
         Override this method if you want to change the way of getting results
diff --git a/framework/tester.py b/framework/tester.py
old mode 100755
new mode 100644
index a775f68..9b665ca
--- a/framework/tester.py
+++ b/framework/tester.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -46,6 +46,9 @@ from utils import GREEN, convert_int2ip, convert_ip2int
 from exception import ParameterInvalidException
 from multiprocessing import Process
 
+from settings import SWITCH
+from switch import Switch
+from exception import SwitchException
 
 class Tester(Crb):
 
@@ -79,6 +82,15 @@ class Tester(Crb):
             self.ixia_packet_gen = IxiaPacketGenerator(self)
         self.packet_gen = SoftwarePacketGenerator(self)
 
+    def init_switch(self):
+        '''
+        Create switch work scene.
+        '''
+        if self.it_uses_switch():
+            switch = Switch()
+            switch.init_scenes(self)
+            self.switch_scenes = switch.switch_grp
+
     def set_re_run(self, re_run_time):
         """
         set failed case re-run time
@@ -127,6 +139,30 @@ class Tester(Crb):
         """
         return load_global_setting(PERF_SETTING) == 'yes' and self.has_external_traffic_generator()
 
+    def get_switch_crb(self):
+        """
+        Return SWITCH object.
+        """
+        return self.crb[SWITCH]
+
+    def has_switch(self):
+        """
+        Check whether test will base on switch equipment.
+        """
+        try:
+            if self.crb[SWITCH] is not None:
+                return True
+        except Exception as e:
+            return False
+
+        return False
+
+    def it_uses_switch(self):
+        """
+        Check whether switch is ready for test.
+        """
+        return self.has_switch()
+
     def tester_prerequisites(self):
         """
         Prerequest function should be called before execute any test case.
@@ -201,6 +237,15 @@ class Tester(Crb):
 
         if self.ports_info[localPort]['type'] == 'ixia':
             return "00:00:00:00:00:01"
+        # switch
+        elif self.ports_info[localPort]['type'] == 'switch':
+            for name, sw_obj in self.switch_scenes.iteritems():
+                if localPort in sw_obj.ports():
+                    mac = sw_obj.get_mac(localPort)
+                    return mac
+            else:
+                msg_fmt = "local port {0} is not in any switch scene".format
+                raise SwitchException(msg_fmt(localPort))
         else:
             return self.ports_info[localPort]['mac']
 
@@ -294,6 +339,9 @@ class Tester(Crb):
             self.scan_ports_uncached()
             if self.it_uses_external_generator():
                 self.ports_info.extend(self.ixia_packet_gen.get_ports())
+            if self.it_uses_switch():
+                for name, sw_obj in self.switch_scenes.iteritems():
+                    self.ports_info.extend(sw_obj.get_ports())
             self.save_serializer_ports()
 
         for port_info in self.ports_info:
@@ -306,6 +354,8 @@ class Tester(Crb):
         for port_info in self.ports_info:
             if port_info['type'] == 'ixia':
                 continue
+            if port_info['type'] == 'switch':
+                continue
 
             addr_array = port_info['pci'].split(':')
             domain_id = addr_array[0]
@@ -394,6 +444,10 @@ class Tester(Crb):
         """
         if self.ports_info[localPort]['type'] == 'ixia':
             return self.ixia_packet_gen.send_ping6(self.ports_info[localPort]['pci'], mac, ipv6)
+        elif self.ports_info[localPort]['type'] == 'switch':
+            for name, sw_obj in self.switch_scenes.iteritems():
+                if localPort in sw_obj.ports():
+                    return 'empty'
         else:
             return self.send_expect("ping6 -w 5 -c 5 -A %s%%%s" % (ipv6, self.ports_info[localPort]['intf']), "# ", 10)
 
@@ -426,6 +480,9 @@ class Tester(Crb):
         if ftype == 'ixia' and dtype != ftype:
             return False
 
+        if ftype == 'switch' and dtype != ftype:
+            return False
+
         return True
 
     def scapy_append(self, cmd):
@@ -502,6 +559,24 @@ class Tester(Crb):
             return None
         return self.packet_gen.throughput(portList, rate_percent)
 
+    def loop_traffic_generator_throughput(self, portList, rate_percent=100, delay=5):
+        """
+        Run throughput performance test on specified ports.
+        """
+        if self.check_port_list(portList, 'ixia'):
+            return self.ixia_packet_gen.loop_throughput(portList, rate_percent, delay)
+        if not self.check_port_list(portList):
+            self.logger.warning("exception by mixed port types")
+            return None
+        result = self.packet_gen.loop_throughput(portList, rate_percent)
+        return result
+
+    def stop_traffic_generator_throughput_loop(self, portList, rate_percent=100, delay=5):
+        """
+        Run throughput performance test on specified ports.
+        """
+        return self.ixia_packet_gen.stop_loop_throughput(portList, rate_percent, delay)
+
     def verify_packet_order(self, portList, delay):
         if self.check_port_list(portList, 'ixia'):
             return self.ixia_packet_gen.is_packet_ordered(portList, delay)
@@ -536,6 +611,41 @@ class Tester(Crb):
             return None
         return self.packet_gen.loss(portList, ratePercent, delay)
 
+    def traffic_get_port_stats(self, portList, delay=60):
+        """
+        Run loss performance test on specified ports.
+        """
+        ratePercent = float(100)
+        if self.check_port_list(portList, 'ixia'):
+            return self.ixia_packet_gen.port_stats(portList, ratePercent, delay)
+        elif not self.check_port_list(portList):
+            self.logger.warning("exception by mixed port types")
+            return None
+        else:
+            return None
+
+    def get_port_line_rate(self):
+        return self.ixia_packet_gen.port_line_rate()
+
+    def loop_traffic_generator_latency(self, portList, ratePercent=100, delay=5):
+        """
+        Run latency performance test on specified ports.
+        """
+        if self.check_port_list(portList, 'ixia'):
+            return self.ixia_packet_gen.loop_latency(portList, ratePercent, delay)
+        else:
+            return None
+
+    def stop_traffic_generator_latency(self, portList, ratePercent=100, delay=5):
+        """
+        Run latency performance test on specified ports.
+        """
+        if self.check_port_list(portList, 'ixia'):
+            return self.ixia_packet_gen.stop_latency(portList, ratePercent, delay)
+        else:
+            return None
+
+
     def traffic_generator_latency(self, portList, ratePercent=100, delay=5):
         """
         Run latency performance test on specified ports.
@@ -725,6 +835,9 @@ class Tester(Crb):
             self.alt_session = None
         if self.it_uses_external_generator():
             self.ixia_packet_gen.close()
+        if self.it_uses_switch():
+            for name, sw_obj in self.switch_scenes.iteritems():
+                sw_obj.close()
 
     def crb_exit(self):
         """
-- 
1.9.3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [dts] [PATCH V1 1/6] pmd_bonded_8023ad: upload test plan
  2018-06-06  5:38 ` [dts] [PATCH V1 1/6] " yufengx.mo
@ 2018-07-06  1:30   ` Liu, Yong
  0 siblings, 0 replies; 9+ messages in thread
From: Liu, Yong @ 2018-07-06  1:30 UTC (permalink / raw)
  To: Mo, YufengX, dts; +Cc: Mo, YufengX

Thanks, Yufen. Some comments are inline.

> -----Original Message-----
> From: dts [mailto:dts-bounces@dpdk.org] On Behalf Of yufengx.mo@intel.com
> Sent: Wednesday, June 06, 2018 1:38 PM
> To: dts@dpdk.org
> Cc: Mo, YufengX <yufengx.mo@intel.com>
> Subject: [dts] [PATCH V1 1/6] pmd_bonded_8023ad: upload test plan
> 
> From: yufengmx <yufengx.mo@intel.com>
> 
> 
> This test plan 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@intel.com>
> ---
>  test_plans/pmd_bonded_8023ad_test_plan.rst | 521
> +++++++++++++++++++++++++++++
>  1 file changed, 521 insertions(+)
>  create mode 100644 test_plans/pmd_bonded_8023ad_test_plan.rst
> 
> diff --git a/test_plans/pmd_bonded_8023ad_test_plan.rst
> b/test_plans/pmd_bonded_8023ad_test_plan.rst
> new file mode 100644
> index 0000000..d871323
> --- /dev/null
> +++ b/test_plans/pmd_bonded_8023ad_test_plan.rst
> @@ -0,0 +1,521 @@
> +.. Copyright (c) <2010-2018>, Intel Corporation
> +   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.
> +
> +Link Bonding for mode 4 (802.3ad)
> +=================================
> +
> +This test plan is mainly to test link bonding mode 4(802.3ad) function
> via
> +testpmd
> +
> +link bonding mode 4 is 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.
> DPDK
> +realize it based on 802.1AX specification, it includes LACP protocal and
> Marker
> +protocol. This mode requires a switch that supports IEEE 802.3ad Dynamic
> link
> +aggregation.
> +
> +note: Slave selection for outgoing traffic is done according to the
> transmit
> +hash policy, which may be changed from the default simple XOR layer2
> policy.
> +
> +**Requirements**
> +
> +* Bonded ports SHALL maintain statistics similar to that of normal ports
> +
> +* The slave links SHALL be monitor for link status change. See also the
> concept
> +  of up/down time delay to handle situations such as a switch reboots, it
> is
> +  possible that its ports report "link up" status before they become
> usable.
> +
> +* Upon unbonding the bonding PMD driver MUST restore the MAC addresses
> that the
> +  slaves had before they were enslaved.
> +
> +* According to the bond type, when the bond interface is placed in
> promiscuous
> +  mode it will propagate the setting to the slave devices.
> +
> +* Generally require that the switch should be compatible with IEEE
> 802.3AD.
> +  e.g. Cisco 5500 series with EtherChannel support or may be called a
> trunk
> +  group.
> +
> +* LACP control packet filtering offload. It is a idea of performance
> +  improvement, which use hardware offloads to improve packet
> classification.
> +
> +  technical details refer to content attached in website
> +  http://dpdk.org/ml/archives/dev/2017-May/066143.html
> +
> +*.support three 802.3ad aggregation selection logic modes
> (stable/bandwidth/
> +  count). The Selection Logic selects a compatible Aggregator for a port,
> using
> +  the port�s LAG ID. The Selection Logic may determine that the link
> should be
> +  operated as a standby link if there are constraints on the simultaneous
> +  attachment of ports that have selected the same Aggregator.
> +
> +  DPDK technical details refer to
> +    ``doc/guides/prog_guide/link_bonding_poll_mode_drv_lib.rst``
> +        ``Link Aggregation 802.3AD (Mode 4)``
> +
> +  Linux technical details refer to ``linux_bonding.txt`` content of
> 802.3ad
> +
> +Prerequisites for Bonding
> +=========================
> +*. additional hardware requirements
> +   a switch that supports IEEE 802.3ad Dynamic link aggregation
> +
> +*. hardware configuration
> +  all link ports of switch/dut should be the same data rate and support
> +  full-duplex.
> +
> +Functional testing hardware configuration
> +-----------------------------------------
> +  NIC and DUT ports requriements.
> +  - Tester: 2 ports of nic
> +  - DUT:    2 ports of nic
> +
> + Connections ports between tester and DUT
> +           Tester                           DUT
> +          .-------.                      .-------.
> +          | port0 | <------------------> | port0 |
> +          | port1 | <------------------> | port1 |
> +          '-------'                      '-------'
> +
> +Performance testing hardware configuration
> +------------------------------------------
> +  NIC/DUT/IXIA/SWITCH ports requriements.
> +  - Tester: 5 ports of nic.
> +    niantic (2x10G) x 3
> +  - IXIA:   1 ixia ports.
> +        10G port
> +  - SWITCH: 4 switch ports.
> +    quanta hp_t3048(10G) / software: ONS CLI 1.0.1.1316-2
> +
> +    Connections ports between IXIA and DUT
> +    -----------------------------------------------------------------
> +                       quanta switch                               DUT
> +                        .---------.                      |
> +                        |   S xe1 | <------------------> | port0 (niantic)
> <---> |
> +                        |   W xe2 | <------------------> | port1 (niantic)
> <---> |
> +    - port-channel <--> |   I     |                      |
> |------> bond_port(port 5)
> +                        |   T xe3 | <------------------> | port2 (niantic)
> <---> |            ^
> +                        |   C xe4 | <------------------> | port3 (niantic)
> <---> |            |
> +                        |   H     |                      |
> |fwd
> +                        '---------'                      |
> |
> +                                                         |
> |
> +                       ixia 10G                          |
> |
> +                |  slot 6 port 5  |  ------------------> | port4
> (niantic)----------------------
> +

Bond-port is better to be placed in DUT side.


> +
> +Test Case : basic behavior start/stop
> +=====================================
> +*. check bonded device stop/start action under frequecy operation status
> +
> +steps::
> +*. bind two ports
> +
> +    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci
> address 2>
> +
> +*. boot up testpmd
> +
> +    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
> +
> +*. run testpmd command of bonding
> +
> +    testpmd> port stop all
> +    testpmd> create bonded device 4 0
> +    testpmd> add bonding slave 0 2
> +    testpmd> add bonding slave 1 2
> +
> +*. loop execute this step 10 times, check if bonded device still work
> +
> +    testpmd> port stop all
> +    testpmd> port start all
> +    testpmd> start
> +    testpmd> show bonding config 2
> +    testpmd> stop
> +
> +*. quit testpmd
> +    testpmd> stop
> +    testpmd> quit
> +
> +Test Case : basic behavior mac
> +==============================
> +*. bonded device's default mac is one of each slave's mac after one slave
> has
> +   been added.
> +*. when no slave attached, mac should be 00:00:00:00:00:00
> +*. slave's mac restore the MAC addresses that the slave has before they
> were
> +   enslaved.
> +
> +steps::
> +*. bind two ports
> +
> +    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci
> address 2>
> +
> +*. boot up testpmd
> +
> +    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
> +
> +*. run testpmd command of bonding
> +
> +    testpmd> port stop all
> +    testpmd> create bonded device 4 0
> +
> +*. check bond device mac should be 00:00:00:00:00:00
> +
> +    testpmd> show bonding config 2
> +
> +*. add two slaves to bond port
> +
> +    testpmd> add bonding slave 0 2
> +    testpmd> add bonding slave 1 2
> +    testpmd> port start all
> +
> +*. check bond device mac should be one of each slave's mac
> +
> +    testpmd> show bonding config 0
> +    testpmd> show bonding config 1
> +    testpmd> show bonding config 2
> +
> +*. quit testpmd
> +    testpmd> stop
> +    testpmd> quit
> +
> +Test Case : basic behavior link up/down
> +=======================================
> +*. bonded device should be down status without slaves
> +*. bonded device device should have the same status of link status
> +*. Active Slaves status should change with the slave status change
> +
> +steps::
> +*. bind two ports
> +
> +    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci
> address 2>
> +
> +*. boot up testpmd
> +
> +    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
> +
> +*. run testpmd command of bonding
> +
> +    testpmd> port stop all
> +    testpmd> create bonded device 4 0
> +    testpmd> add bonding slave 0 2
> +    testpmd> add bonding slave 1 2
> +
> +*. stop bonded device and check bonded device/slaves link status
> +
> +    testpmd> port stop 2
> +    testpmd> show bonding config 2
> +    testpmd> show bonding config 1
> +    testpmd> show bonding config 0
> +
> +*. start bonded device and check bonded device/slaves link status
> +
> +    testpmd> port start 2
> +    testpmd> show bonding config 2
> +    testpmd> show bonding config 1
> +    testpmd> show bonding config 0
> +
> +*. quit testpmd
> +    testpmd> stop
> +    testpmd> quit
> +
> +Test Case : basic behavior promisc mode
> +=======================================
> +*. bonded device promiscuous mode should be ``enabled`` by default
> +*. bonded device/slave device should have the same status of promiscuous
> mode
> +
> +steps::
> +*. bind two ports
> +
> +    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci
> address 2>
> +
> +*. boot up testpmd
> +
> +    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
> +
> +*. run testpmd command of bonding
> +
> +    testpmd> port stop all
> +    testpmd> create bonded device 4 0
> +
> +*. check if bonded device promiscuous mode is ``enabled``
> +
> +    testpmd> show bonding config 2
> +
> +*. add two slaves and check if promiscuous mode is ``enabled``
> +
> +    testpmd> add bonding slave 0 2
> +    testpmd> add bonding slave 1 2
> +    testpmd> show bonding config 0
> +    testpmd> show bonding config 1
> +
> +*. disable bonded device promiscuous mode and check promiscuous mode
> +
> +    testpmd> set promisc 2 off
> +    testpmd> show bonding config 2
> +
> +*. enable bonded device promiscuous mode and check promiscuous mode
> +
> +    testpmd> set promisc 2 on
> +    testpmd> show bonding config 2
> +
> +*. check slaves' promiscuous mode
> +
> +    testpmd> show bonding config 0
> +    testpmd> show bonding config 1
> +
> +*. quit testpmd
> +    testpmd> stop
> +    testpmd> quit
> +
> +Test Case : basic behavior agg mode
> +===================================
> +*. stable is the default agg mode
> +*. check 802.3ad aggregation mode configuration
> +support <agg_option>:
> +``count``
> +``stable``
> +``bandwidth``
> +
Hi Yufen,
Could you move the description of mode configuration here?

> +steps::
> +*. bind two ports
> +
> +    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci
> address 2>
> +
> +*. boot up testpmd
> +
> +    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
> +
> +*. run testpmd command of bonding
> +
> +    testpmd> port stop all
> +    testpmd> create bonded device 4 0
> +    testpmd> add bonding slave 0 2
> +    testpmd> add bonding slave 1 2
> +    testpmd> port start all
> +    testpmd> show bonding config 2
> +    testpmd> set bonding agg_mode 2 <agg_option>
> +
> +*. check if agg_mode set successful
> +
> +    testpmd> show bonding config 2
> +        Bonding mode: 4
> +        IEEE802.3AD Aggregator Mode: <agg_option>
> +        Slaves (2): [0 1]
> +        Active Slaves (2): [0 1]
> +        Primary: [0]
> +
> +*. quit testpmd
> +    testpmd> stop
> +    testpmd> quit
> +
> +Test Case : basic behavior dedicated queues
> +===========================================
> +*. check 802.3ad dedicated queues is ``disable`` by default
> +*. check 802.3ad set dedicated queues
> +support <agg_option>:
> +``disable``
> +``enable``
> +

Yufen,
Could you please add some background introduction for dedicated queue setting?

> +steps:
> +*. bind two ports
> +
> +    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci
> address 2>
> +
> +*. boot up testpmd
> +
> +    ./testpmd -c 0xXXXXX -n 4  -- -i --tx-offloads=0xXXXX
> +
> +*. run testpmd command of bonding
> +
> +    testpmd> port stop all
> +    testpmd> create bonded device 4 0
> +    testpmd> add bonding slave 0 2
> +    testpmd> add bonding slave 1 2
> +    testpmd> show bonding config 2
> +
> +*. check if dedicated_queues disable successful
> +
> +    testpmd> set bonding lacp dedicated_queues 2 disable
> +
> +*. check if bonded port can start
> +
> +    testpmd> port start all
> +    testpmd> start
> +
> +*. check if dedicated_queues enable successful
> +
> +    testpmd> stop
> +    testpmd> port stop all
> +    testpmd> set bonding lacp dedicated_queues 2 enable
> +
> +*. check if bonded port can start
> +
> +    testpmd> port start all
> +    testpmd> start
> +
> +*. quit testpmd
> +    testpmd> stop
> +    testpmd> quit
> +
> +Test Case : command line option
> +===============================
> +*. check command line option
> +slave=<0000:xx:00.0>
> +agg_mode=<bandwidth | stable | count>
> +*. compare bonding configuration with expected configuration.
> +
> +steps:
> +*. bind two ports
> +
> +    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci
> address 2>
> +
> +
> +*. boot up testpmd
> +
> +    ./testpmd -c 0x0f -n 4 \
> +    --vdev
> 'net_bonding0,slave=0000:xx:00.0,slave=0000:xx:00.1,mode=4,agg_mode=<agg_o
> ption>'  \
> +    -- -i --port-topology=chained
> +
> +*. run testpmd command of bonding
> +
> +    testpmd> port stop all
> +
> +*. check if bonded device has been created and slaves have been bonded
> successful
> +
> +    testpmd> show bonding config 2
> +        Bonding mode: 4
> +        IEEE802.3AD Aggregator Mode: <agg_option>
> +        Slaves (2): [0 1]
> +        Active Slaves (2): [0 1]
> +        Primary: [0]
> +
> +*. check if bonded port can start
> +
> +    testpmd> port start all
> +    testpmd> start
> +
> +*. check if dedicated_queues enable successful

No idea about why dedicated queue related to aggregate mode, please explain it.

> +
> +    testpmd> stop
> +    testpmd> port stop all
> +
> +*. quit testpmd
> +    testpmd> quit
> +
> +
> +Test Case : tx agg mode stable
> +==============================
> +stable: use slaves[default_slave] as index
> +        The active aggregator is chosen by largest aggregate
> +        bandwidth.
> +
> +        Reselection of the active aggregator occurs only when all
> +        slaves of the active aggregator are down or the active
> +        aggregator has no slaves.
> +
> +steps:
> +*. quanta switch setting
> +    vlan 100
> +    port-channel 4000
> +    slave interface: xe1/xe2/xe3/xe4
> +
> +*. dut port 1-4 link to quanta switch xe1/xe2/xe3/xe4
> +
> +*. dut port 5 link to ixia
> +
> +*. bind five ports
> +
> +    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci
> address 2> \
> +    <pci address 3> <pci address 4> <pci address 5>
> +
> +*. boot up testpmd with 4 slave ports
> +
> +    ./testpmd -c 0x0f -n 4 \
> +    --vdev
> 'net_bonding0,slave=0000:xx:00.0,slave=0000:xx:00.1,slave=0000:xx:00.2,sla
> ve=0000:xx:00.3,mode=4,agg_mode=stable' \
> +    -- -i --port-topology=chained
> +
> +*. packet setting, udp packet(in folder "stream_abcd")
> +
> +    [Ether(dst=nutmac, src=srcmac)/IP(dst=destip, src=srcip,
> len=46)/UDP(sport=srcport, dport=destport)/Raw(load='P'*26)
> +
> +    create flow_a/flow_b/flow_c/flow_d stream flow
> +
> +*. start ixia traffic
> +
> +    ixia_stream=(flow_a+flow_b+flow_c+flow_d)
> +    10G line rate run at percentPacketRate(100%)
> +    traffic lasting 250 second or so
> +
> +*. run testpmd command of bonding, ixia traffic is forward from port 4 to
> bond port 5
> +
> +    testpmd> port stop all
> +    testpmd> set bonding lacp dedicated_queues 5 enable
> +    testpmd> set portlist 0,5
> +    testpmd> port start all
> +    testpmd> start
> +
> +*. keep ixia traffic lasting 5 minutes
> +
> +*. stop ixia and get ixia statistcis
> +
> +*. stop testpmd and get ixia statistcis
> +
> +    testpmd> stop
> +    testpmd> port stop all
> +    testpmd> show port stats all
> +
> +*. get quanta switch xe1/xe2/xe3/xe4 statistcis
> +
> +*. compare switch statistcis with testpmd statistcis
> +

Some typos here, statistcis should be statistics. 

> +Test Case : tx agg mode count
> +=============================
> +count:  use agg_count amount as index
> +        The active aggregator is chosen by the largest number of
> +        ports (slaves).  Reselection occurs as described under the
> +        "bandwidth/count mode aggregator reselection".
> +
> +steps are the same as ``tx agg mode count``,  change the testpmd command
> as
> +
> +    ./testpmd -c 0x0f -n 4 \
> +    --vdev
> 'net_bonding0,slave=0000:xx:00.0,slave=0000:xx:00.1,slave=0000:xx:00.2,sla
> ve=0000:xx:00.3,mode=4,agg_mode=count' \
> +    -- -i --port-topology=chained
> +
> +Test Case : tx agg mode bandwidth
> +=================================
> +bandwidth: use link_speed amount as index
> +        The active aggregator is chosen by largest aggregate
> +        bandwidth. Reselection occurs as described under the
> +        "bandwidth/count mode aggregator reselection".
> +
> +steps are the same as ``tx agg mode count``,  change the testpmd command
> as
> +
> +    ./testpmd -c 0x0f -n 4 \
> +    --vdev
> 'net_bonding0,slave=0000:xx:00.0,slave=0000:xx:00.1,slave=0000:xx:00.2,sla
> ve=0000:xx:00.3,mode=4,agg_mode=bandwidth' \
> +    -- -i --port-topology=chained
> \ No newline at end of file
> --
> 1.9.3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [dts] [PATCH V1 2/6] pmd_bonded_8023ad: upload automation script
  2018-06-06  5:38 ` [dts] [PATCH V1 2/6] pmd_bonded_8023ad: upload automation script yufengx.mo
@ 2019-01-21  7:19   ` Chen, Zhaoyan
  0 siblings, 0 replies; 9+ messages in thread
From: Chen, Zhaoyan @ 2019-01-21  7:19 UTC (permalink / raw)
  To: Mo, YufengX, dts; +Cc: Mo, YufengX, Tu, Lijuan, Chen, Zhaoyan

Yufeng,

- Please extract the common functions into common file and share between each bond test suite.
- Remove "Switch" related code. 




Regards,
Zhaoyan Chen


> -----Original Message-----
> From: dts [mailto:dts-bounces@dpdk.org] On Behalf Of yufengx.mo@intel.com
> Sent: Wednesday, June 6, 2018 1:38 PM
> To: dts@dpdk.org
> Cc: Mo, YufengX <yufengx.mo@intel.com>
> Subject: [dts] [PATCH V1 2/6] pmd_bonded_8023ad: upload automation script
> 
> From: yufengmx <yufengx.mo@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@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

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-01-21  7:19 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-06  5:38 [dts] [PATCH V1 0/6] pmd_bonded_8023ad: upload test plan yufengx.mo
2018-06-06  5:38 ` [dts] [PATCH V1 1/6] " yufengx.mo
2018-07-06  1:30   ` Liu, Yong
2018-06-06  5:38 ` [dts] [PATCH V1 2/6] pmd_bonded_8023ad: upload automation script yufengx.mo
2019-01-21  7:19   ` Chen, Zhaoyan
2018-06-06  5:38 ` [dts] [PATCH V1 3/6] pmd_bonded_8023ad: add switch module in dts/framework yufengx.mo
2018-06-06  5:38 ` [dts] [PATCH V1 4/6] pmd_bonded_8023ad: dts configuration files yufengx.mo
2018-06-06  5:38 ` [dts] [PATCH V1 5/6] pmd_bonded_8023ad: framework work flow yufengx.mo
2018-06-06  5:38 ` [dts] [PATCH V1 6/6] pmd_bonded_8023ad: framework etgen/ixia yufengx.mo

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).