get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/121601/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 121601,
    "url": "https://patches.dpdk.org/api/patches/121601/?format=api",
    "web_url": "https://patches.dpdk.org/project/dts/patch/20230105110752.235201-6-songx.jiale@intel.com/",
    "project": {
        "id": 3,
        "url": "https://patches.dpdk.org/api/projects/3/?format=api",
        "name": "DTS",
        "link_name": "dts",
        "list_id": "dts.dpdk.org",
        "list_email": "dts@dpdk.org",
        "web_url": "",
        "scm_url": "git://dpdk.org/tools/dts",
        "webscm_url": "http://git.dpdk.org/tools/dts/",
        "list_archive_url": "https://inbox.dpdk.org/dts",
        "list_archive_url_format": "https://inbox.dpdk.org/dts/{}",
        "commit_url_format": ""
    },
    "msgid": "<20230105110752.235201-6-songx.jiale@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dts/20230105110752.235201-6-songx.jiale@intel.com",
    "date": "2023-01-05T11:07:50",
    "name": "[V1,5/7] tests/vf_pmd_stacked_bonded: add cases to test vf bonding",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "fced846154598427e42d55e26fcdfccac9fff797",
    "submitter": {
        "id": 2352,
        "url": "https://patches.dpdk.org/api/people/2352/?format=api",
        "name": "Jiale, SongX",
        "email": "songx.jiale@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dts/patch/20230105110752.235201-6-songx.jiale@intel.com/mbox/",
    "series": [
        {
            "id": 26392,
            "url": "https://patches.dpdk.org/api/series/26392/?format=api",
            "web_url": "https://patches.dpdk.org/project/dts/list/?series=26392",
            "date": "2023-01-05T11:07:45",
            "name": "add cases to test vf bonding",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/26392/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/121601/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/121601/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dts-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 602EDA00C2;\n\tThu,  5 Jan 2023 04:10:14 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 57DB642D20;\n\tThu,  5 Jan 2023 04:10:14 +0100 (CET)",
            "from mga06.intel.com (mga06b.intel.com [134.134.136.31])\n by mails.dpdk.org (Postfix) with ESMTP id 2220242D21\n for <dts@dpdk.org>; Thu,  5 Jan 2023 04:10:11 +0100 (CET)",
            "from orsmga008.jf.intel.com ([10.7.209.65])\n by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 04 Jan 2023 19:10:11 -0800",
            "from unknown (HELO localhost.localdomain) ([10.239.252.20])\n by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 04 Jan 2023 19:10:10 -0800"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1672888211; x=1704424211;\n h=from:to:cc:subject:date:message-id:in-reply-to:\n references:mime-version:content-transfer-encoding;\n bh=P7LaTu7E1cZFTXh/amMKOD4XrtiFiP8IxO4S6AEhs64=;\n b=IvqXIPAXxAPO0rd/DnPMFrkIiFicIQMNxhVYG/uswe/9we/VGOKAcUVW\n OJcjAT3pQDqYXb2W0lTbbJ8826URlkYRlw07puKQ4MYcnFq7E3QnrWrgS\n hLI6Qsd6Kmm79WERn/JnxBeu+hiMTEI0SKM8Be14bVuLhJrPaUJMzKvO9\n lqv2tXSj3ibteG9xY1n/3MyR61HJjdq3j1V0Cw4+Qf5ZYgTq1RroY0NjW\n d3e33Bc6sucxpsEhUHKpcX9xGbe+dIvIkSXFwoLcBWUg3lqrdlcOEfQPu\n AXd4AyeHiGhVsxUJcXojADZf9NNLfY2eep8qcqdVvQeXtP/PVHofJwdVD w==;",
        "X-IronPort-AV": [
            "E=McAfee;i=\"6500,9779,10580\"; a=\"384398314\"",
            "E=Sophos;i=\"5.96,301,1665471600\"; d=\"scan'208\";a=\"384398314\"",
            "E=McAfee;i=\"6500,9779,10580\"; a=\"685949746\"",
            "E=Sophos;i=\"5.96,301,1665471600\"; d=\"scan'208\";a=\"685949746\""
        ],
        "From": "Song Jiale <songx.jiale@intel.com>",
        "To": "dts@dpdk.org",
        "Cc": "Song Jiale <songx.jiale@intel.com>",
        "Subject": "[dts] [PATCH V1 5/7] tests/vf_pmd_stacked_bonded: add cases to test\n vf bonding",
        "Date": "Thu,  5 Jan 2023 11:07:50 +0000",
        "Message-Id": "<20230105110752.235201-6-songx.jiale@intel.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20230105110752.235201-1-songx.jiale@intel.com>",
        "References": "<20230105110752.235201-1-songx.jiale@intel.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "dts@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "test suite reviews and discussions <dts.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dts>,\n <mailto:dts-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dts/>",
        "List-Post": "<mailto:dts@dpdk.org>",
        "List-Help": "<mailto:dts-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dts>,\n <mailto:dts-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dts-bounces@dpdk.org"
    },
    "content": "add case to test vf bonding.\n\nSigned-off-by: Song Jiale <songx.jiale@intel.com>\n---\n tests/TestSuite_vf_pmd_stacked_bonded.py | 614 +++++++++++++++++++++++\n 1 file changed, 614 insertions(+)\n create mode 100644 tests/TestSuite_vf_pmd_stacked_bonded.py",
    "diff": "diff --git a/tests/TestSuite_vf_pmd_stacked_bonded.py b/tests/TestSuite_vf_pmd_stacked_bonded.py\nnew file mode 100644\nindex 00000000..e8556684\n--- /dev/null\n+++ b/tests/TestSuite_vf_pmd_stacked_bonded.py\n@@ -0,0 +1,614 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2023 Intel Corporation\n+#\n+\n+import time\n+import traceback\n+\n+# import dts/framework libs\n+import framework.utils as utils\n+\n+# import bonding lib\n+import tests.bonding as bonding\n+from framework.exception import VerifyFailure\n+from framework.test_case import TestCase\n+\n+from .bonding import (\n+    FRAME_SIZE_64,\n+    MODE_ACTIVE_BACKUP,\n+    MODE_ALB_BALANCE,\n+    MODE_BROADCAST,\n+    MODE_LACP,\n+    MODE_ROUND_ROBIN,\n+    MODE_TLB_BALANCE,\n+    MODE_XOR_BALANCE,\n+)\n+\n+\n+class TestBondingStacked(TestCase):\n+\n+    #\n+    # On dut, dpdk bonding\n+    #\n+    def check_bonded_device_queue_config(self, *devices):\n+        \"\"\"\n+        check if master bonded device/slave device queue configuration\n+        is the same.\n+        \"\"\"\n+        # get master bonded device queue configuration\n+        master = self.bond_inst.get_port_info(devices[0], \"queue_config\")\n+        # get slave device queue configuration\n+        for port_id in devices[1:]:\n+            config = self.bond_inst.get_port_info(port_id, \"queue_config\")\n+            if config == master:\n+                continue\n+            msg = (\n+                \"slave bonded port [{0}] is \" \"different to top bonded port [{1}]\"\n+            ).format(port_id, devices[0])\n+            raise VerifyFailure(\"bonded device queue config:: \" + msg)\n+\n+    def set_stacked_bonded(self, slaveGrpOne, slaveGrpTwo, bond_mode, ignore=False):\n+        \"\"\"\n+        set stacked bonded mode for a custom bonding mode\n+        \"\"\"\n+        inst = self.bond_inst\n+        socket_id = self.dut.get_numa_id(self.bond_slave)\n+        # create first bonded device 1, add slaves in it\n+        bond_port_1 = inst.create_bonded_device(bond_mode, socket_id)\n+        inst.add_slave(bond_port_1, False, \"\", *slaveGrpOne)\n+        # create second bonded device 2, add slaves in it\n+        bond_port_2 = inst.create_bonded_device(bond_mode, socket_id)\n+        inst.add_slave(bond_port_2, False, \"\", *slaveGrpTwo)\n+        # create master bonded device 3, which is the top bonded device\n+        master_bond_port = inst.create_bonded_device(bond_mode, socket_id)\n+        # add bond bonded device 1 to bonded device 3\n+        # check bonding config status\n+        inst.add_slave(master_bond_port, False, \"\", *[bond_port_1])\n+        # add bonded device 2 to bonded device 3\n+        # check bonding config status\n+        inst.add_slave(master_bond_port, False, \"\", *[bond_port_2])\n+        # check if master bonding/each slaves queue configuration is the same.\n+        if not ignore:\n+            self.check_bonded_device_queue_config(\n+                *[master_bond_port, bond_port_1, bond_port_2]\n+            )\n+\n+        return [bond_port_1, bond_port_2, master_bond_port]\n+\n+    def set_third_stacked_bonded(self, bond_port, bond_mode):\n+        \"\"\"\n+        set third level stacked bonded to check if stacked level can be set\n+        more than 2\n+        \"\"\"\n+        inst = self.bond_inst\n+        socket_id = self.dut.get_numa_id(self.bond_slave)\n+        third_bond_port = inst.create_bonded_device(bond_mode, socket_id)\n+        inst.add_slave(third_bond_port, False, \"\", *[bond_port])\n+\n+    def duplicate_add_stacked_bonded(self, bond_port_1, bond_port_2, master_bond_port):\n+        \"\"\"\n+        check if adding duplicate stacked bonded device is forbidden\n+        \"\"\"\n+        inst = self.bond_inst\n+        # check exception process\n+        expected_str = \"Slave device is already a slave of a bonded device\"\n+        # add bonded device 1 to bonded device 3\n+        # check bonding config status\n+        inst.add_slave(master_bond_port, False, expected_str, *[bond_port_1])\n+        # add bonded device 2 to bonded device 3\n+        # check bonding config status\n+        inst.add_slave(master_bond_port, False, expected_str, *[bond_port_2])\n+\n+    def preset_stacked_bonded(self, slaveGrpOne, slaveGrpTwo, bond_mode):\n+        bond_port_1, bond_port_2, master_bond_port = self.set_stacked_bonded(\n+            slaveGrpOne, slaveGrpTwo, bond_mode, ignore=True\n+        )\n+        portList = [\n+            slaveGrpOne[0],\n+            slaveGrpTwo[0],\n+            bond_port_1,\n+            bond_port_2,\n+            master_bond_port,\n+        ]\n+        cmds = [\n+            [\"port stop all\", \"\"],\n+            [\"set portlist \" + \",\".join([str(port) for port in portList]), \"\"],\n+            # start top level bond port only, and let it propagate the start\n+            # action to slave bond ports and its the real nics.\n+            [\"port start {}\".format(master_bond_port), \" \", 15],\n+        ]\n+        self.bond_inst.d_console(cmds)\n+        # blank space command is used to skip LSC event to avoid core dumped issue\n+        time.sleep(5)\n+        cmds = [[\" \", \"\"], [\"start\", \"\"]]\n+        self.bond_inst.d_console(cmds)\n+        time.sleep(5)\n+\n+        return bond_port_1, bond_port_2, master_bond_port\n+\n+    def send_packets_by_scapy(self, **kwargs):\n+        tx_iface = kwargs.get(\"port topo\")[0]\n+        # set interface ready to send packet\n+        self.dut1 = self.dut.new_session()\n+        cmd = \"ifconfig {0} up\".format(tx_iface)\n+        self.dut1.send_expect(cmd, \"# \", 30)\n+        send_pkts = kwargs.get(\"stream\")\n+        # stream config\n+        stream_configs = kwargs.get(\"traffic configs\")\n+        count = stream_configs.get(\"count\")\n+        interval = stream_configs.get(\"interval\", 0.01)\n+        # run traffic\n+        self.dut1.send_expect(\"scapy\", \">>> \", 30)\n+        cmd = (\n+            \"sendp(\"\n+            + send_pkts[0].command()\n+            + f',iface=\"{tx_iface}\",count={count},inter={interval},verbose=False)'\n+        )\n+        self.dut1.send_expect(cmd, \">>> \")\n+        self.dut1.send_expect(\"quit()\", \"# \")\n+        self.dut.close_session(self.dut1)\n+\n+    #\n+    # packet transmission\n+    #\n+    def traffic(self, traffic_config, ports, tport_is_up=True):\n+        # get ports statistics before sending packets\n+        stats_pre = self.bond_inst.get_all_stats(ports)\n+        # send packets\n+        if tport_is_up:\n+            self.bond_inst.send_packet(traffic_config)\n+        else:\n+            self.send_packets_by_scapy(**traffic_config)\n+        # get ports statistics after sending packets\n+        stats_post = self.bond_inst.get_all_stats(ports)\n+        # calculate ports statistics result\n+        for port_id in ports:\n+            stats_post[port_id][\"RX-packets\"] -= stats_pre[port_id][\"RX-packets\"]\n+            stats_post[port_id][\"TX-packets\"] -= stats_pre[port_id][\"TX-packets\"]\n+\n+        return stats_post\n+\n+    def config_port_traffic(self, tx_port, rx_port, total_pkt):\n+        \"\"\"set traffic configuration\"\"\"\n+        traffic_config = {\n+            \"port topo\": [tx_port, rx_port],\n+            \"stream\": self.bond_inst.set_stream_to_slave_port(rx_port),\n+            \"traffic configs\": {\n+                \"count\": total_pkt,\n+            },\n+        }\n+\n+        return traffic_config\n+\n+    def active_slave_rx(self, slave, bond_port, mode):\n+        msg = \"send packet to active slave port <{0}>\".format(slave)\n+        self.logger.info(msg)\n+        if slave in [0, 1]:\n+            tx_intf = self.tester.get_interface(\n+                self.tester.get_local_port(self.dut_ports[0])\n+            )\n+        elif slave in [2, 3]:\n+            tx_intf = self.tester.get_interface(\n+                self.tester.get_local_port(self.dut_ports[1])\n+            )\n+        else:\n+            self.verify(False, \"Error slave port <{0}>\".format(slave))\n+        # get traffic config\n+        traffic_config = self.config_port_traffic(tx_intf, slave, self.total_pkt)\n+        # select ports for statistics\n+        ports = [slave, bond_port]\n+        # run traffic\n+        stats = self.traffic(traffic_config, ports)\n+        # check slave statistics\n+        msg = \"port <{0}> Data not received by port <{1}>\".format(tx_intf, slave)\n+        # here using `>=` to ignore some miscellaneous packets, e.g. lldp\n+        self.verify(stats[slave][\"RX-packets\"] >= self.total_pkt, msg)\n+        msg = \"tester port {0}  <----> VF port {1} is ok\".format(tx_intf, slave)\n+        self.logger.info(msg)\n+        # check bond port statistics\n+        # here using `>=` to ignore some miscellaneous packets, e.g. lldp\n+        self.verify(\n+            stats[slave][\"RX-packets\"] >= self.total_pkt,\n+            \"Bond port have error RX packet in XOR\",\n+        )\n+\n+    def inactive_slave_rx(self, slave, bond_port, mode):\n+        msg = \"send packet to inactive slave port <{0}>\".format(slave)\n+        self.logger.info(msg)\n+        tx_intf = self.dport_ifaces\n+        # get traffic config\n+        traffic_config = self.config_port_traffic(tx_intf, slave, self.total_pkt)\n+        # select ports for statistics\n+        ports = [slave, bond_port]\n+        # run traffic\n+        stats = self.traffic(traffic_config, ports, tport_is_up=False)\n+        # check slave statistics\n+        msg = (\"port <{0}> Data received by port <{1}>, \" \"but should not.\").format(\n+            tx_intf, slave\n+        )\n+        self.verify(stats[slave][\"RX-packets\"] == 0, msg)\n+        msg = \"tester port {0}  <-|  |-> VF port {1} is blocked\".format(tx_intf, slave)\n+        self.logger.info(msg)\n+        # check bond port statistics\n+        self.verify(\n+            stats[slave][\"RX-packets\"] == 0,\n+            \"Bond port have error RX packet in {0}\".format(mode),\n+        )\n+\n+    def set_port_status(self, vfs_id, tport_inface, status):\n+        # stop slave link by force\n+        cmd = \"ifconfig {0} {1}\".format(tport_inface, status)\n+        self.tester.send_expect(cmd, \"# \")\n+        time.sleep(3)\n+        vfs_id = vfs_id if isinstance(vfs_id, list) else [vfs_id]\n+        for vf in vfs_id:\n+            cur_status = self.bond_inst.get_port_info(vf, \"link_status\")\n+            self.logger.info(\"port {0} is [{1}]\".format(vf, cur_status))\n+            self.verify(cur_status == status, \"expected status is [{0}]\".format(status))\n+\n+    def check_traffic_with_one_slave_down(self, mode):\n+        \"\"\"\n+        Verify that transmitting packets correctly when set one slave of\n+        the bonded device link down.\n+        \"\"\"\n+        results = []\n+        # -------------------------------\n+        # boot up testpmd\n+        self.bond_inst.start_testpmd(self.eal_param)\n+        self.bond_inst.d_console(\"set fwd mac\")\n+        try:\n+            slaves = {\"active\": [], \"inactive\": []}\n+            # -------------------------------\n+            # preset stacked bonded device\n+            slaveGrpOne = self.slaveGrpOne\n+            slaveGrpTwo = self.slaveGrpTwo\n+            bond_port_1, bond_port_2, master_bond_port = self.preset_stacked_bonded(\n+                slaveGrpOne, slaveGrpTwo, mode\n+            )\n+            # ---------------------------------------------------\n+            # set one slave of first bonded device and second bonded device link down\n+            bond1_primary_slave = slaveGrpOne[0]\n+            bond2_primary_slave = slaveGrpTwo[0]\n+            # self.bond_inst.set_dut_port_status(primary_slave, \"down\")\n+            self.set_port_status(\n+                vfs_id=[0, 1], tport_inface=self.tport_iface0, status=\"down\"\n+            )\n+            slaves[\"inactive\"].append(bond1_primary_slave)\n+            # get slave status\n+            primary_port, active_slaves = self.bond_inst.get_active_slaves(bond_port_1)\n+            slaves[\"active\"].extend(active_slaves)\n+            if bond1_primary_slave in slaves[\"active\"]:\n+                msg = \"{0} should not be in active slaves list\".format(\n+                    bond1_primary_slave\n+                )\n+                raise Exception(msg)\n+            slaves[\"inactive\"].append(bond2_primary_slave)\n+            # check active slaves\n+            primary_port_2, active_slaves_2 = self.bond_inst.get_active_slaves(\n+                bond_port_2\n+            )\n+            slaves[\"active\"].extend(active_slaves_2)\n+            if bond2_primary_slave in slaves[\"active\"]:\n+                msg = \"{0} should not be in active slaves list\".format(\n+                    bond2_primary_slave\n+                )\n+                raise Exception(msg)\n+            # traffic testing\n+            # active slave traffic testing\n+            for slave in slaves[\"active\"]:\n+                self.active_slave_rx(slave, master_bond_port, mode)\n+            # inactive slave traffic testing\n+            for slave in slaves[\"inactive\"]:\n+                self.inactive_slave_rx(slave, master_bond_port, mode)\n+        except Exception as e:\n+            results.append(e)\n+            self.logger.error(traceback.format_exc())\n+        finally:\n+            self.bond_inst.close_testpmd()\n+\n+        return results\n+\n+    def check_traffic(self, mode):\n+        \"\"\"normal traffic with all slaves are under active status.\n+        verify the RX packets are all correct with stacked bonded device.\n+        bonded device's statistics should be the sum of slaves statistics.\n+        \"\"\"\n+        self.bond_inst.start_testpmd(self.eal_param)\n+        self.bond_inst.d_console(\"set fwd mac\")\n+        slaveGrpOne = self.slaveGrpOne\n+        slaveGrpTwo = self.slaveGrpTwo\n+        bond_port_1, bond_port_2, master_bond_port = self.preset_stacked_bonded(\n+            slaveGrpOne, slaveGrpTwo, mode\n+        )\n+        results = []\n+        # check first bonded device\n+        try:\n+            self.logger.info(\"check first bonded device\")\n+            # active slave traffic testing\n+            for slave in slaveGrpOne:\n+                self.active_slave_rx(slave, bond_port_1, mode)\n+        except Exception as e:\n+            results.append(e)\n+        # check second bonded device\n+        try:\n+            self.logger.info(\"check second bonded device\")\n+            # active slave traffic testing\n+            for slave in slaveGrpOne:\n+                self.active_slave_rx(slave, bond_port_2, mode)\n+        except Exception as e:\n+            results.append(e)\n+\n+        # check top bonded device\n+        try:\n+            self.logger.info(\"check master bonded device\")\n+            # active slave traffic testing\n+            for slave in slaveGrpOne + slaveGrpTwo:\n+                self.active_slave_rx(slave, master_bond_port, mode)\n+        except Exception as e:\n+            results.append(e)\n+\n+        self.bond_inst.close_testpmd()\n+\n+        return results\n+\n+    def backup_check_traffic(self):\n+        mode = MODE_ACTIVE_BACKUP\n+        msg = \"begin checking bonding backup(stacked) mode transmission\"\n+        self.logger.info(msg)\n+        results = self.check_traffic(mode)\n+        if results:\n+            for item in results:\n+                self.logger.error(item)\n+            raise VerifyFailure(\"backup(stacked) mode: rx failed\")\n+\n+    def backup_check_traffic_with_slave_down(self):\n+        mode = MODE_ACTIVE_BACKUP\n+        self.logger.info(\n+            \"begin checking bonding backup(stacked) \"\n+            \"mode transmission with one slave down\"\n+        )\n+        results = self.check_traffic_with_one_slave_down(mode)\n+        if results:\n+            for item in results:\n+                self.logger.error(item)\n+            msg = \"backup(stacked) mode: rx with one slave down failed\"\n+            raise VerifyFailure(msg)\n+\n+    def xor_check_rx(self):\n+        mode = MODE_XOR_BALANCE\n+        msg = \"begin checking bonding xor(stacked) mode transmission\"\n+        self.logger.info(msg)\n+        results = self.check_traffic(mode)\n+        if results:\n+            for item in results:\n+                self.logger.error(item)\n+            raise VerifyFailure(\"xor(stacked) mode: rx failed\")\n+\n+    def xor_check_stacked_rx_one_slave_down(self):\n+        mode = MODE_XOR_BALANCE\n+        self.logger.info(\n+            \"begin checking bonding xor(stacked) mode \"\n+            \"transmission with one slave down\"\n+        )\n+        results = self.check_traffic_with_one_slave_down(mode)\n+        if results:\n+            for item in results:\n+                self.logger.error(item)\n+            msg = \"xor(stacked) mode: rx with one slave down failed\"\n+            raise VerifyFailure(msg)\n+\n+    #\n+    # Test cases.\n+    #\n+    def set_up_all(self):\n+        \"\"\"\n+        Run before each test suite\n+        \"\"\"\n+        self.verify(\"bsdapp\" not in self.target, \"Bonding not support freebsd\")\n+        self.dut_ports = self.dut.get_ports()\n+        self.dport_info0 = self.dut.ports_info[self.dut_ports[0]]\n+        self.dport_ifaces = self.dport_info0[\"intf\"]\n+        num_ports = len(self.dut_ports)\n+        self.verify(num_ports == 2 or num_ports == 4, \"Insufficient ports\")\n+        tester_port0 = self.tester.get_local_port(self.dut_ports[0])\n+        self.tport_iface0 = self.tester.get_interface(tester_port0)\n+        self.flag = \"link-down-on-close\"\n+        self.default_stats = self.tester.get_priv_flags_state(\n+            self.tport_iface0, self.flag\n+        )\n+        self.tester.send_expect(\n+            \"ethtool --set-priv-flags %s %s on\" % (self.tport_iface0, self.flag), \"# \"\n+        )\n+        tester_port1 = self.tester.get_local_port(self.dut_ports[1])\n+        self.tport_iface1 = self.tester.get_interface(tester_port1)\n+        self.tester.send_expect(\n+            \"ethtool --set-priv-flags %s %s on\" % (self.tport_iface1, self.flag), \"# \"\n+        )\n+        # separate ports into two group as first level bond ports' slaves\n+        self.slaveGrpOne = [0, 2]\n+        self.slaveGrpTwo = [1, 3]\n+        self.bond_slave = self.dut_ports[0]\n+        # initialize bonding common methods name\n+        self.total_pkt = 100\n+        config = {\n+            \"parent\": self,\n+            \"pkt_name\": \"udp\",\n+            \"pkt_size\": FRAME_SIZE_64,\n+            \"src_mac\": \"52:00:00:00:00:03\",\n+            \"src_ip\": \"10.239.129.65\",\n+            \"src_port\": 61,\n+            \"dst_ip\": \"10.239.129.88\",\n+            \"dst_port\": 53,\n+        }\n+        self.bond_inst = bonding.PmdBonding(**config)\n+\n+    def tear_down_all(self):\n+        \"\"\"\n+        Run after each test suite.\n+        \"\"\"\n+        self.tester.send_expect(\n+            \"ethtool --set-priv-flags %s %s %s\"\n+            % (self.tport_iface0, self.flag, self.default_stats),\n+            \"# \",\n+        )\n+        self.tester.send_expect(\n+            \"ethtool --set-priv-flags %s %s %s\"\n+            % (self.tport_iface1, self.flag, self.default_stats),\n+            \"# \",\n+        )\n+\n+    def set_up(self):\n+        \"\"\"\n+        Run before each test case.\n+        \"\"\"\n+        self.create_vfs(pfs_id=self.dut_ports[0:2], vf_num=2)\n+        self.eal_param = \"\"\n+        for pci in self.vfs_pci:\n+            self.eal_param += \" -a %s\" % pci\n+\n+    def create_vfs(self, pfs_id, vf_num):\n+        self.sriov_vfs_port = []\n+        self.vfs_pci = []\n+        self.dut.bind_interfaces_linux(self.kdriver)\n+        pfs_id = pfs_id if isinstance(pfs_id, list) else [pfs_id]\n+        for pf_id in pfs_id:\n+            self.dut.generate_sriov_vfs_by_port(pf_id, vf_num)\n+            self.sriov_vfs_port += self.dut.ports_info[self.dut_ports[pf_id]][\n+                \"vfs_port\"\n+            ]\n+        for vf in self.sriov_vfs_port:\n+            self.vfs_pci.append(vf.pci)\n+        try:\n+            for port in self.sriov_vfs_port:\n+                port.bind_driver(self.drivername)\n+        except Exception as e:\n+            self.destroy_iavf()\n+            raise Exception(e)\n+\n+    def destroy_iavf(self):\n+        self.dut.destroy_sriov_vfs_by_port(self.dut_ports[0])\n+\n+    def tear_down(self):\n+        \"\"\"\n+        Run after each test case.\n+        \"\"\"\n+        try:\n+            self.bond_inst.close_testpmd()\n+        except Exception:\n+            self.dut.kill_all()\n+        self.destroy_iavf()\n+        for port in self.dut_ports:\n+            tport = self.tester.get_local_port(port)\n+            tport_iface = self.tester.get_interface(tport)\n+            cmd = \"ifconfig {0} up\".format(tport_iface)\n+            self.tester.send_expect(cmd, \"# \")\n+\n+    def test_basic_behav(self):\n+        \"\"\"\n+        Test Case: basic behavior\n+        allow a bonded device to be added to another bonded device.\n+        There's two limitations to create master bonding:\n+\n+         - Total depth of nesting is limited to two levels,\n+         - 802.3ad mode is not supported if one or more slaves is a bond device\n+\n+        note: There 802.3ad mode can not be supported on this bond device.\n+\n+        This case is aimed at testing basic behavior of stacked bonded commands.\n+\n+        \"\"\"\n+        # ------------------------------------------------\n+        # check stacked bonded status, except mode 4 (802.3ad)\n+        mode_list = [\n+            MODE_ROUND_ROBIN,\n+            MODE_ACTIVE_BACKUP,\n+            MODE_XOR_BALANCE,\n+            MODE_BROADCAST,\n+            MODE_TLB_BALANCE,\n+            MODE_ALB_BALANCE,\n+        ]\n+        slaveGrpOne = self.slaveGrpOne\n+        slaveGrpTwo = self.slaveGrpTwo\n+        check_result = []\n+        for bond_mode in mode_list:\n+            self.logger.info(\"begin mode <{0}> checking\".format(bond_mode))\n+            # boot up testpmd\n+            self.bond_inst.start_testpmd(self.eal_param)\n+            self.bond_inst.d_console(\"set fwd mac\")\n+            try:\n+                self.logger.info(\"check bonding mode <{0}>\".format(bond_mode))\n+                # set up stacked bonded status\n+                bond_port_1, bond_port_2, master_bond_port = self.set_stacked_bonded(\n+                    slaveGrpOne, slaveGrpTwo, bond_mode\n+                )\n+                # check duplicate add slave\n+                self.duplicate_add_stacked_bonded(\n+                    bond_port_1, bond_port_2, master_bond_port\n+                )\n+                # check stacked limitation\n+                self.set_third_stacked_bonded(master_bond_port, bond_mode)\n+                # quit testpmd, it is not supported to reset testpmd\n+                self.logger.info(\"mode <{0}> done !\".format(bond_mode))\n+                check_result.append([bond_mode, None])\n+            except Exception as e:\n+                check_result.append([bond_mode, e])\n+                self.logger.error(e)\n+            finally:\n+                self.bond_inst.close_testpmd()\n+                time.sleep(5)\n+        # ------------------------------------------------\n+        # 802.3ad mode is not supported\n+        # if one or more slaves is a bond device\n+        # so it should raise a exception\n+        msg = \"\"\n+        try:\n+            # boot up testpmd\n+            self.bond_inst.start_testpmd(self.eal_param)\n+            # set up stacked bonded status\n+            self.set_stacked_bonded(slaveGrpOne, slaveGrpTwo, MODE_LACP)\n+            # quit testpmd, it is not supported to reset testpmd\n+            msg = \"802.3ad mode hasn't been forbidden to \" \"use stacked bonded setting\"\n+            check_result.append([MODE_LACP, msg])\n+        except Exception as e:\n+            check_result.append([MODE_LACP, None])\n+        finally:\n+            self.bond_inst.close_testpmd()\n+\n+        exception_flag = False\n+        for bond_mode, e in check_result:\n+            msg = \"mode <{0}>\".format(bond_mode)\n+            if e:\n+                self.logger.info(msg)\n+                self.logger.error(e)\n+                exception_flag = True\n+            else:\n+                self.logger.info(msg + \" done !\")\n+        # if some checking item is failed, raise exception\n+        if exception_flag:\n+            raise VerifyFailure(\"some test items failed\")\n+        else:\n+            self.logger.info(\"all test items have done !\")\n+\n+    def test_mode_backup_rx(self):\n+        \"\"\"\n+        Test Case: active-backup stacked bonded rx traffic\n+        \"\"\"\n+        self.backup_check_traffic()\n+\n+    def test_mode_backup_one_slave_down(self):\n+        \"\"\"\n+        Test Case: active-backup stacked bonded rx traffic with slave down\n+        \"\"\"\n+        self.backup_check_traffic_with_slave_down()\n+\n+    def test_mode_xor_rx(self):\n+        \"\"\"\n+        Test Case: balance-xor stacked bonded rx traffic\n+        \"\"\"\n+        self.xor_check_rx()\n+\n+    def test_mode_xor_rx_one_slave_down(self):\n+        \"\"\"\n+        Test Case: balance-xor stacked bonded rx traffic with slave down\n+        \"\"\"\n+        self.xor_check_stacked_rx_one_slave_down()\n",
    "prefixes": [
        "V1",
        "5/7"
    ]
}