get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 607,
    "url": "http://patchwork.dpdk.org/api/patches/607/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/1411746081-19550-1-git-send-email-danielx.t.mrzyglod@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1411746081-19550-1-git-send-email-danielx.t.mrzyglod@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1411746081-19550-1-git-send-email-danielx.t.mrzyglod@intel.com",
    "date": "2014-09-26T15:41:21",
    "name": "[dpdk-dev,v2] ADD mode 5(tlb) to link bonding pmd",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "46102745cedbcb186b36bed0166ec7b04de1911a",
    "submitter": {
        "id": 23,
        "url": "http://patchwork.dpdk.org/api/people/23/?format=api",
        "name": "Daniel Mrzyglod",
        "email": "danielx.t.mrzyglod@intel.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/1411746081-19550-1-git-send-email-danielx.t.mrzyglod@intel.com/mbox/",
    "series": [],
    "comments": "http://patchwork.dpdk.org/api/patches/607/comments/",
    "check": "pending",
    "checks": "http://patchwork.dpdk.org/api/patches/607/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 365847E13;\n\tFri, 26 Sep 2014 17:35:40 +0200 (CEST)",
            "from mga03.intel.com (mga03.intel.com [134.134.136.65])\n\tby dpdk.org (Postfix) with ESMTP id 350317E10\n\tfor <dev@dpdk.org>; Fri, 26 Sep 2014 17:35:38 +0200 (CEST)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n\tby orsmga103.jf.intel.com with ESMTP; 26 Sep 2014 08:39:56 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga001.jf.intel.com with ESMTP; 26 Sep 2014 08:41:57 -0700",
            "from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com\n\t[10.237.217.46])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\ts8QFfu7Y000882; Fri, 26 Sep 2014 16:41:56 +0100",
            "from sivswdev02.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev02.ir.intel.com with ESMTP id s8QFfuC2019819;\n\tFri, 26 Sep 2014 16:41:56 +0100",
            "(from dtmrzglx@localhost)\n\tby sivswdev02.ir.intel.com with  id s8QFfuJC019759;\n\tFri, 26 Sep 2014 16:41:56 +0100"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.04,604,1406617200\"; d=\"scan'208\";a=\"579541132\"",
        "From": "Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri, 26 Sep 2014 16:41:21 +0100",
        "Message-Id": "<1411746081-19550-1-git-send-email-danielx.t.mrzyglod@intel.com>",
        "X-Mailer": "git-send-email 1.7.4.1",
        "Subject": "[dpdk-dev] [PATCH v2] ADD mode 5(tlb) to link bonding pmd",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>\n---\n app/test/test_link_bonding.c               |  501 +++++++++++++++++++++++++++-\n app/test/virtual_pmd.c                     |    6 +-\n app/test/virtual_pmd.h                     |    7 +\n lib/librte_pmd_bond/rte_eth_bond.h         |   23 ++\n lib/librte_pmd_bond/rte_eth_bond_args.c    |    1 +\n lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  161 ++++++++-\n lib/librte_pmd_bond/rte_eth_bond_private.h |    3 +-\n 7 files changed, 696 insertions(+), 6 deletions(-)",
    "diff": "diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c\nindex c4fcaf7..77f791f 100644\n--- a/app/test/test_link_bonding.c\n+++ b/app/test/test_link_bonding.c\n@@ -41,7 +41,7 @@\n #include <errno.h>\n #include <sys/queue.h>\n #include <sys/time.h>\n-\n+#include <rte_cycles.h>\n #include <rte_byteorder.h>\n #include <rte_common.h>\n #include <rte_debug.h>\n@@ -3845,6 +3845,500 @@ testsuite_teardown(void)\n \treturn remove_slaves_and_stop_bonded_device();\n }\n \n+#define NINETY_PERCENT_NUMERAL 90\n+#define ONE_HUNDRED_PERCENT_DENOMINATOR 100\n+#define ONE_HUNDRED_PERCENT_AND_TEN_NUMERAL 110\n+static int\n+test_tlb_tx_burst(void)\n+{\n+\tint i, burst_size, nb_tx;\n+\tuint64_t nb_tx2 = 0;\n+\tstruct rte_mbuf *pkt_burst[MAX_PKT_BURST];\n+\tstruct rte_eth_stats port_stats[32];\n+\tuint64_t sum_ports_opackets = 0, all_bond_opackets = 0, all_bond_obytes = 0;\n+\tuint16_t pktlen;\n+\n+\tTEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves\n+\t\t\t(BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 1, 3, 1),\n+\t\t\t\"Failed to initialise bonded device\");\n+\n+\tburst_size = 20 * test_params->bonded_slave_count;\n+\n+\tTEST_ASSERT(burst_size < MAX_PKT_BURST,\n+\t\t\t\"Burst size specified is greater than supported.\\n\");\n+\n+\n+\t/* Generate 400000 test bursts in 2s of packets to transmit  */\n+\tfor (i = 0; i < 400000; i++) {\n+\t\t/*test two types of mac src own(bonding) and others */\n+\t\tif (i % 2 == 0) {\n+\t\t\tinitialize_eth_header(test_params->pkt_eth_hdr,\n+\t\t\t\t\t(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);\n+\t\t} else {\n+\t\t\tinitialize_eth_header(test_params->pkt_eth_hdr,\n+\t\t\t\t\t(struct ether_addr *)test_params->default_slave_mac,\n+\t\t\t\t\t(struct ether_addr *)dst_mac_0, 0, 0);\n+\t\t}\n+\t\tpktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,\n+\t\t\t\tdst_port_0, 16);\n+\t\tpktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,\n+\t\t\t\tdst_addr_0, pktlen);\n+\t\tgenerate_packet_burst(test_params->mbuf_pool, pkt_burst,\n+\t\t\t\ttest_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr,\n+\t\t\t\t1, test_params->pkt_udp_hdr, burst_size, 60, 1);\n+\t\t/* Send burst on bonded port */\n+\t\tnb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst,\n+\t\t\t\tburst_size);\n+\t\tnb_tx2 += nb_tx;\n+\n+\t\tTEST_ASSERT_EQUAL(nb_tx, burst_size,\n+\t\t\t\t\"number of packet not equal burst size\");\n+\n+\t\trte_delay_us(5);\n+\t}\n+\n+\n+\t/* Verify bonded port tx stats */\n+\trte_eth_stats_get(test_params->bonded_port_id, &port_stats[0]);\n+\n+\tall_bond_opackets = port_stats[0].opackets;\n+\tall_bond_obytes = port_stats[0].obytes;\n+\n+\tTEST_ASSERT_EQUAL(port_stats[0].opackets, (uint64_t)nb_tx2,\n+\t\t\t\"Bonded Port (%d) opackets value (%u) not as expected (%d)\\n\",\n+\t\t\ttest_params->bonded_port_id, (unsigned int)port_stats[0].opackets,\n+\t\t\tburst_size);\n+\n+\n+\t/* Verify slave ports tx stats */\n+\tfor (i = 0; i < test_params->bonded_slave_count; i++) {\n+\t\trte_eth_stats_get(test_params->slave_port_ids[i], &port_stats[i]);\n+\t\tsum_ports_opackets += port_stats[i].opackets;\n+\t}\n+\n+\tTEST_ASSERT_EQUAL(sum_ports_opackets, (uint64_t)all_bond_opackets,\n+\t\t\t\"Total packets sent by slaves is not equalto packets sent by bond interface\");\n+\n+\tfor (i = 0; i < test_params->bonded_slave_count; i++) {\n+\t\tprintf(\"port stats:%\"PRIu64\"\\n\", port_stats[i].opackets);\n+\t\t/* distribution of packets on each slave within +/- 10% of the expected value. */\n+\t\tTEST_ASSERT(port_stats[i].obytes >= ((all_bond_obytes*NINETY_PERCENT_NUMERAL)/\n+\t\t\t\t(test_params->bonded_slave_count*ONE_HUNDRED_PERCENT_DENOMINATOR)) &&\n+\t\t\t\tport_stats[i].obytes <= ((all_bond_obytes*ONE_HUNDRED_PERCENT_AND_TEN_NUMERAL) /\n+\t\t\t\t\t\t(test_params->bonded_slave_count*ONE_HUNDRED_PERCENT_DENOMINATOR)),\n+\t\t\t\t\t\t\"Distribution is not even\");\n+\t}\n+\t/* Put all slaves down and try and transmit */\n+\tfor (i = 0; i < test_params->bonded_slave_count; i++) {\n+\t\tvirtual_ethdev_simulate_link_status_interrupt(\n+\t\t\t\ttest_params->slave_port_ids[i], 0);\n+\t}\n+\n+\t/* Send burst on bonded port */\n+\tnb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst,\n+\t\t\tburst_size);\n+\tTEST_ASSERT_EQUAL(nb_tx, 0, \" bad number of packet in burst\");\n+\n+\t/* Clean ugit checkout masterp and remove slaves from bonded device */\n+\treturn remove_slaves_and_stop_bonded_device();\n+}\n+\n+#define TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT (4)\n+\n+static int\n+test_tlb_rx_burst(void)\n+{\n+\tstruct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL };\n+\tstruct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };\n+\n+\tstruct rte_eth_stats port_stats;\n+\n+\tint primary_port;\n+\n+\tuint16_t i, j, nb_rx, burst_size = 17;\n+\n+\t/* Initialize bonded device with 4 slaves in transmit load balancing mode */\n+\tTEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(\n+\t\t\tBONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING,\n+\t\t\tTEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1, 1),\n+\t\t\t\"Failed to initialize bonded device\");\n+\n+\n+\tprimary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);\n+\tTEST_ASSERT(primary_port >= 0,\n+\t\t\t\"failed to get primary slave for bonded port (%d)\",\n+\t\t\ttest_params->bonded_port_id);\n+\n+\tfor (i = 0; i < test_params->bonded_slave_count; i++) {\n+\t\t/* Generate test bursts of packets to transmit */\n+\t\tTEST_ASSERT_EQUAL(generate_test_burst(\n+\t\t\t\t&gen_pkt_burst[0], burst_size, 0, 1, 0, 0, 0), burst_size,\n+\t\t\t\t\"burst generation failed\");\n+\n+\t\t/* Add rx data to slave */\n+\t\tvirtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],\n+\t\t\t\t&gen_pkt_burst[0], burst_size);\n+\n+\t\t/* Call rx burst on bonded device */\n+\t\tnb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0,\n+\t\t\t\t&rx_pkt_burst[0], MAX_PKT_BURST);\n+\n+\t\tTEST_ASSERT_EQUAL(nb_rx,burst_size,\"rte_eth_rx_burst failed\\n\");\n+\n+\t\tif (test_params->slave_port_ids[i] == primary_port) {\n+\t\t\t/* Verify bonded device rx count */\n+\t\t\trte_eth_stats_get(test_params->bonded_port_id, &port_stats);\n+\t\t\tTEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size,\n+\t\t\t\t\t\"Bonded Port (%d) ipackets value (%u) not as expected (%d)\\n\",\n+\t\t\t\t\ttest_params->bonded_port_id,\n+\t\t\t\t\t(unsigned int)port_stats.ipackets, burst_size);\n+\n+\t\t\t/* Verify bonded slave devices rx count */\n+\t\t\tfor (j = 0; j < test_params->bonded_slave_count; j++) {\n+\t\t\t\trte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);\n+\t\t\t\tif (i == j) {\n+\t\t\t\t\tTEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size,\n+\t\t\t\t\t\t\t\"Slave Port (%d) ipackets value (%u) not as expected (%d)\\n\",\n+\t\t\t\t\t\t\ttest_params->slave_port_ids[i],\n+\t\t\t\t\t\t\t(unsigned int)port_stats.ipackets, burst_size);\n+\t\t\t\t} else {\n+\t\t\t\t\tTEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)0,\n+\t\t\t\t\t\t\t\"Slave Port (%d) ipackets value (%u) not as expected (%d)\\n\",\n+\t\t\t\t\t\t\ttest_params->slave_port_ids[i],\n+\t\t\t\t\t\t\t(unsigned int)port_stats.ipackets, 0);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} else {\n+\t\t\tfor (j = 0; j < test_params->bonded_slave_count; j++) {\n+\t\t\t\trte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);\n+\t\t\t\tTEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)0,\n+\t\t\t\t\t\t\"Slave Port (%d) ipackets value (%u) not as expected (%d)\\n\",\n+\t\t\t\t\t\ttest_params->slave_port_ids[i],\n+\t\t\t\t\t\t(unsigned int)port_stats.ipackets, 0);\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* free mbufs */\n+\t\tfor (i = 0; i < burst_size; i++)\n+\t\t\trte_pktmbuf_free(rx_pkt_burst[i]);\n+\n+\t\t/* reset bonded device stats */\n+\t\trte_eth_stats_reset(test_params->bonded_port_id);\n+\t}\n+\n+\t/* Clean up and remove slaves from bonded device */\n+\treturn remove_slaves_and_stop_bonded_device();\n+}\n+\n+static int\n+test_tlb_verify_promiscuous_enable_disable(void)\n+{\n+\tint i, primary_port, promiscuous_en;\n+\n+\t/* Initialize bonded device with 4 slaves in transmit load balancing mode */\n+\tTEST_ASSERT_SUCCESS( initialize_bonded_device_with_slaves(\n+\t\t\tBONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 4, 1),\n+\t\t\t\"Failed to initialize bonded device\");\n+\n+\tprimary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);\n+\tTEST_ASSERT(primary_port >= 0,\n+\t\t\t\"failed to get primary slave for bonded port (%d)\",\n+\t\t\ttest_params->bonded_port_id);\n+\n+\trte_eth_promiscuous_enable(test_params->bonded_port_id);\n+\n+\tpromiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);\n+\tTEST_ASSERT_EQUAL(promiscuous_en, (int)1,\n+\t\t\t\"Port (%d) promiscuous mode not enabled\\n\",\n+\t\t\ttest_params->bonded_port_id);\n+\tfor (i = 0; i < test_params->bonded_slave_count; i++) {\n+\t\tpromiscuous_en = rte_eth_promiscuous_get(\n+\t\t\t\ttest_params->slave_port_ids[i]);\n+\t\tif (primary_port == test_params->slave_port_ids[i]) {\n+\t\t\tTEST_ASSERT_EQUAL(promiscuous_en, (int)1,\n+\t\t\t\t\t\"Port (%d) promiscuous mode not enabled\\n\",\n+\t\t\t\t\ttest_params->bonded_port_id);\n+\t\t} else {\n+\t\t\tTEST_ASSERT_EQUAL(promiscuous_en, (int)0,\n+\t\t\t\t\t\"Port (%d) promiscuous mode enabled\\n\",\n+\t\t\t\t\ttest_params->bonded_port_id);\n+\t\t}\n+\n+\t}\n+\n+\trte_eth_promiscuous_disable(test_params->bonded_port_id);\n+\n+\tpromiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);\n+\tTEST_ASSERT_EQUAL(promiscuous_en, (int)0,\n+\t\t\t\"Port (%d) promiscuous mode not disabled\\n\",\n+\t\t\ttest_params->bonded_port_id);\n+\n+\tfor (i = 0; i < test_params->bonded_slave_count; i++) {\n+\t\tpromiscuous_en = rte_eth_promiscuous_get(\n+\t\t\t\ttest_params->slave_port_ids[i]);\n+\t\tTEST_ASSERT_EQUAL(promiscuous_en, (int)0,\n+\t\t\t\t\"slave port (%d) promiscuous mode not disabled\\n\",\n+\t\t\t\ttest_params->slave_port_ids[i]);\n+\t}\n+\n+\t/* Clean up and remove slaves from bonded device */\n+\treturn remove_slaves_and_stop_bonded_device();\n+}\n+\n+static int\n+test_tlb_verify_mac_assignment(void)\n+{\n+\tstruct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;\n+\n+\trte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);\n+\trte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1);\n+\n+\t/* Initialize bonded device with 2 slaves in active backup mode */\n+\tTEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(\n+\t\t\tBONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 2, 1),\n+\t\t\t\"Failed to initialize bonded device\");\n+\n+\t/* Verify that bonded MACs is that of first slave and that the other slave\n+\t * MAC hasn't been changed */\n+\trte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"bonded port (%d) mac address not set to that of primary port\",\n+\t\t\ttest_params->bonded_port_id);\n+\n+\trte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"slave port (%d) mac address not set to that of primary port\",\n+\t\t\ttest_params->slave_port_ids[0]);\n+\n+\trte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"slave port (%d) mac address not as expected\",\n+\t\t\ttest_params->slave_port_ids[1]);\n+\n+\t/* change primary and verify that MAC addresses haven't changed */\n+\tTEST_ASSERT_EQUAL(rte_eth_bond_primary_set(test_params->bonded_port_id,\n+\t\t\ttest_params->slave_port_ids[1]), 0,\n+\t\t\t\"Failed to set bonded port (%d) primary port to (%d)\",\n+\t\t\ttest_params->bonded_port_id, test_params->slave_port_ids[1]);\n+\n+\trte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"bonded port (%d) mac address not set to that of primary port\",\n+\t\t\ttest_params->bonded_port_id);\n+\n+\trte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"slave port (%d) mac address not set to that of primary port\",\n+\t\t\ttest_params->slave_port_ids[0]);\n+\n+\trte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"slave port (%d) mac address not as expected\",\n+\t\t\ttest_params->slave_port_ids[1]);\n+\n+\t/* stop / start bonded device and verify that primary MAC address is\n+\t * propagated to bonded device and slaves */\n+\n+\trte_eth_dev_stop(test_params->bonded_port_id);\n+\n+\tTEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params->bonded_port_id),\n+\t\t\t\"Failed to start device\");\n+\n+\trte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"bonded port (%d) mac address not set to that of primary port\",\n+\t\t\ttest_params->bonded_port_id);\n+\n+\trte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"slave port (%d) mac address not as expected\",\n+\t\t\ttest_params->slave_port_ids[0]);\n+\n+\trte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"slave port (%d) mac address not set to that of primary port\",\n+\t\t\ttest_params->slave_port_ids[1]);\n+\n+\n+\t/* Set explicit MAC address */\n+\tTEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_set(\n+\t\t\ttest_params->bonded_port_id, (struct ether_addr *)bonded_mac),\n+\t\t\t\"failed to set MAC addres\");\n+\n+\trte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"bonded port (%d) mac address not set to that of bonded port\",\n+\t\t\ttest_params->bonded_port_id);\n+\n+\trte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"slave port (%d) mac address not as expected\",\n+\t\t\ttest_params->slave_port_ids[0]);\n+\n+\trte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);\n+\tTEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr,\n+\t\t\tsizeof(read_mac_addr)),\n+\t\t\t\"slave port (%d) mac address not set to that of bonded port\",\n+\t\t\ttest_params->slave_port_ids[1]);\n+\n+\t/* Clean up and remove slaves from bonded device */\n+\treturn remove_slaves_and_stop_bonded_device();\n+}\n+\n+static int\n+test_tlb_verify_slave_link_status_change_failover(void)\n+{\n+\tstruct rte_mbuf *pkt_burst[TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT][MAX_PKT_BURST];\n+\tstruct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };\n+\tstruct rte_eth_stats port_stats;\n+\n+\tuint8_t slaves[RTE_MAX_ETHPORTS];\n+\n+\tint i, j, burst_size, slave_count, primary_port;\n+\n+\tburst_size = 21;\n+\n+\tmemset(pkt_burst, 0, sizeof(pkt_burst));\n+\n+\n+\n+\t/* Initialize bonded device with 4 slaves in round robin mode */\n+\tTEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(\n+\t\t\tBONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0,\n+\t\t\tTEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1),\n+\t\t\t\"Failed to initialize bonded device with slaves\");\n+\n+\t/* Verify Current Slaves Count /Active Slave Count is */\n+\tslave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, slaves,\n+\t\t\tRTE_MAX_ETHPORTS);\n+\tTEST_ASSERT_EQUAL(slave_count, 4,\n+\t\t\t\"Number of slaves (%d) is not as expected (%d).\\n\",\n+\t\t\tslave_count, 4);\n+\n+\tslave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,\n+\t\t\tslaves, RTE_MAX_ETHPORTS);\n+\tTEST_ASSERT_EQUAL(slave_count, (int)4,\n+\t\t\t\"Number of slaves (%d) is not as expected (%d).\\n\",\n+\t\t\tslave_count, 4);\n+\n+\tprimary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);\n+\tTEST_ASSERT_EQUAL(primary_port, test_params->slave_port_ids[0],\n+\t\t\t\"Primary port not as expected\");\n+\n+\t/* Bring 2 slaves down and verify active slave count */\n+\tvirtual_ethdev_simulate_link_status_interrupt(\n+\t\t\ttest_params->slave_port_ids[1], 0);\n+\tvirtual_ethdev_simulate_link_status_interrupt(\n+\t\t\ttest_params->slave_port_ids[3], 0);\n+\n+\tTEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get(\n+\t\t\ttest_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS), 2,\n+\t\t\t\"Number of active slaves (%d) is not as expected (%d).\",\n+\t\t\tslave_count, 2);\n+\n+\tvirtual_ethdev_simulate_link_status_interrupt(\n+\t\t\ttest_params->slave_port_ids[1], 1);\n+\tvirtual_ethdev_simulate_link_status_interrupt(\n+\t\t\ttest_params->slave_port_ids[3], 1);\n+\n+\n+\t/* Bring primary port down, verify that active slave count is 3 and primary\n+\t *  has changed */\n+\tvirtual_ethdev_simulate_link_status_interrupt(\n+\t\t\ttest_params->slave_port_ids[0], 0);\n+\n+\tTEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get(\n+\t\t\ttest_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS), 3,\n+\t\t\t\"Number of active slaves (%d) is not as expected (%d).\",\n+\t\t\tslave_count, 3);\n+\n+\tprimary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);\n+\tTEST_ASSERT_EQUAL(primary_port, test_params->slave_port_ids[2],\n+\t\t\t\"Primary port not as expected\");\n+\trte_delay_us(500000);\n+\t/* Verify that pkts are sent on new primary slave */\n+\tfor (i = 0; i < 4; i++) {\n+\t\tTEST_ASSERT_EQUAL(generate_test_burst(\n+\t\t\t\t&pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0), burst_size,\n+\t\t\t\t\"generate_test_burst failed\\n\");\n+\t\tTEST_ASSERT_EQUAL(rte_eth_tx_burst(\n+\t\t\t\ttest_params->bonded_port_id, 0, &pkt_burst[0][0], burst_size), burst_size,\n+\t\t\t\t\"rte_eth_tx_burst failed\\n\");\n+\t\trte_delay_us(11000);\n+\t}\n+\n+\trte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);\n+\tTEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,\n+\t\t\t\"(%d) port_stats.opackets not as expected\\n\",\n+\t\t\ttest_params->slave_port_ids[2]);\n+\n+\trte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);\n+\tTEST_ASSERT_EQUAL(port_stats.opackets, (int8_t)0,\n+\t\t\t\"(%d) port_stats.opackets not as expected\\n\",\n+\t\t\ttest_params->slave_port_ids[0]);\n+\n+\trte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);\n+\tTEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,\n+\t\t\t\"(%d) port_stats.opackets not as expected\\n\",\n+\t\t\ttest_params->slave_port_ids[1]);\n+\n+\trte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);\n+\tTEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,\n+\t\t\t\"(%d) port_stats.opackets not as expected\\n\",\n+\t\t\ttest_params->slave_port_ids[3]);\n+\n+\n+\t/* Generate packet burst for testing */\n+\n+\tfor (i = 0; i < TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT; i++) {\n+\t\tif (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0) !=\n+\t\t\t\tburst_size)\n+\t\t\treturn -1;\n+\n+\t\tvirtual_ethdev_add_mbufs_to_rx_queue(\n+\t\t\t\ttest_params->slave_port_ids[i], &pkt_burst[i][0], burst_size);\n+\t}\n+\n+\tif (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,\n+\t\t\tMAX_PKT_BURST) != burst_size) {\n+\t\tprintf(\"rte_eth_rx_burst\\n\");\n+\t\treturn -1;\n+\n+\t}\n+\n+\t/* Verify bonded device rx count */\n+\trte_eth_stats_get(test_params->bonded_port_id, &port_stats);\n+\tTEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size,\n+\t\t\t\"(%d) port_stats.ipackets not as expected\\n\",\n+\t\t\ttest_params->bonded_port_id);\n+\n+\t/* free mbufs */\n+\n+\tfor (i = 0; i < TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT; i++) {\n+\t\tfor (j = 0; j < MAX_PKT_BURST; j++) {\n+\t\t\tif (pkt_burst[i][j] != NULL) {\n+\t\t\t\trte_pktmbuf_free(pkt_burst[i][j]);\n+\t\t\t\tpkt_burst[i][j] = NULL;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\n+\t/* Clean up and remove slaves from bonded device */\n+\treturn remove_slaves_and_stop_bonded_device();\n+}\n+\n \n static struct unit_test_suite link_bonding_test_suite  = {\n \t.suite_name = \"Link Bonding Unit Test Suite\",\n@@ -3898,6 +4392,11 @@ static struct unit_test_suite link_bonding_test_suite  = {\n \t\tTEST_CASE(test_balance_verify_promiscuous_enable_disable),\n \t\tTEST_CASE(test_balance_verify_mac_assignment),\n \t\tTEST_CASE(test_balance_verify_slave_link_status_change_behaviour),\n+\t\tTEST_CASE(test_tlb_tx_burst),\n+\t\tTEST_CASE(test_tlb_rx_burst),\n+\t\tTEST_CASE(test_tlb_verify_mac_assignment),\n+\t\tTEST_CASE(test_tlb_verify_promiscuous_enable_disable),\n+\t\tTEST_CASE(test_tlb_verify_slave_link_status_change_failover),\n \t\tTEST_CASE(test_broadcast_tx_burst),\n \t\tTEST_CASE(test_broadcast_tx_burst_slave_tx_fail),\n \t\tTEST_CASE(test_broadcast_rx_burst),\ndiff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c\nindex fffaa35..331bec3 100644\n--- a/app/test/virtual_pmd.c\n+++ b/app/test/virtual_pmd.c\n@@ -359,16 +359,18 @@ virtual_ethdev_tx_burst_success(void *queue, struct rte_mbuf **bufs,\n \n \tstruct rte_eth_dev *vrtl_eth_dev;\n \tstruct virtual_ethdev_private *dev_private;\n-\n+\tuint64_t obytes = 0;\n \tint i;\n \n+\tfor (i = 0; i < nb_pkts; i++)\n+\t\tobytes += rte_pktmbuf_pkt_len(bufs[i]);\n \tvrtl_eth_dev = &rte_eth_devices[tx_q->port_id];\n \tdev_private = vrtl_eth_dev->data->dev_private;\n \n \tif (vrtl_eth_dev->data->dev_link.link_status) {\n \t\t/* increment opacket count */\n \t\tdev_private->eth_stats.opackets += nb_pkts;\n-\n+\t\tdev_private->eth_stats.obytes += obytes;\n \t\t/* free packets in burst */\n \t\tfor (i = 0; i < nb_pkts; i++) {\n \t\t\trte_pktmbuf_free(bufs[i]);\ndiff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h\nindex 2462853..4118e3e 100644\n--- a/app/test/virtual_pmd.h\n+++ b/app/test/virtual_pmd.h\n@@ -94,6 +94,13 @@ void\n virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id,\n \t\tuint8_t packet_fail_count);\n \n+/* if a value greater than zero is set for packet_fail_count then virtual\n+ * device tx burst function will fail that many packet from burst or all\n+ * packets if packet_fail_count is greater than the number of packets in the\n+ * burst */\n+void virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id,\n+\t\tuint8_t packet_fail_count);\n+\n #ifdef __cplusplus\n }\n #endif\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h\nindex 6811c7b..682e5c7 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond.h\n+++ b/lib/librte_pmd_bond/rte_eth_bond.h\n@@ -75,6 +75,29 @@ extern \"C\" {\n /**< Broadcast (Mode 3).\n  * In this mode all transmitted packets will be transmitted on all available\n  * active slaves of the bonded. */\n+#define BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING\t(5)\n+/**< Broadcast (Mode 5)\n+ * Adaptive transmit load balancing: channel bonding that\n+ * does not require any special switch support.  The\n+ * outgoing traffic is distributed according to the\n+ * current load (computed relative to the speed) on each\n+ * slave.  Incoming traffic is received by the current\n+ * slave.  If the receiving slave fails, another slave\n+ * takes over the MAC address of the failed receiving\n+ * slave.*/\n+#define BONDING_MODE_ADAPTIVE_LOAD_BALANCING\t\t\t(6)\n+/**\n+ * Adaptive load balancing: includes balance-tlb plus\n+ * receive load balancing (rlb) for IPV4 traffic, and\n+ * does not require any special switch support.  The\n+ * receive load balancing is achieved by ARP negotiation.\n+ * The bonding driver intercepts the ARP Replies sent by\n+ * the local system on their way out and overwrites the\n+ * source hardware address with the unique hardware\n+ * address of one of the slaves in the bond such that\n+ * different peers use different hardware addresses for\n+ * the server. */\n+\n \n /* Balance Mode Transmit Policies */\n #define BALANCE_XMIT_POLICY_LAYER2\t\t(0)\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c\nindex bbbc69b..7464af5 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_args.c\n+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c\n@@ -171,6 +171,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n \tcase BONDING_MODE_BALANCE:\n \tcase BONDING_MODE_BROADCAST:\n+\tcase BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:\n \t\treturn 0;\n \tdefault:\n \t\tRTE_BOND_LOG(ERR, \"Invalid slave mode value (%s) specified\", value);\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c\nindex 6d0fb1b..db6a934 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c\n+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c\n@@ -30,7 +30,7 @@\n  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n  */\n-\n+#include <stdlib.h>\n #include <rte_mbuf.h>\n #include <rte_malloc.h>\n #include <rte_ethdev.h>\n@@ -41,10 +41,13 @@\n #include <rte_kvargs.h>\n #include <rte_dev.h>\n #include <rte_alarm.h>\n+#include <rte_cycles.h>\n \n #include \"rte_eth_bond.h\"\n #include \"rte_eth_bond_private.h\"\n \n+#define REORDER_PERIOD_MS 10\n+\n static uint16_t\n bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n {\n@@ -287,6 +290,141 @@ xmit_slave_hash(const struct rte_mbuf *buf, uint8_t slave_count, uint8_t policy)\n \treturn hash % slave_count;\n }\n \n+struct bwg_slave {\n+\tuint64_t bwg_left_int;\n+\tuint64_t bwg_left_remainder;\n+\tuint8_t slave;\n+};\n+\n+static int\n+bandwidth_cmp(const void *a, const void *b)\n+{\n+\tconst struct bwg_slave *bwg_a = a;\n+\tconst struct bwg_slave *bwg_b = b;\n+\tint64_t diff = (int64_t)bwg_b->bwg_left_int - (int64_t)bwg_a->bwg_left_int;\n+\tint64_t diff2 = (int64_t)bwg_b->bwg_left_remainder -\n+\t\t\t(int64_t)bwg_a->bwg_left_remainder;\n+\tif (diff > 0)\n+\t\treturn 1;\n+\telse if (diff < 0)\n+\t\treturn -1;\n+\telse if (diff2 > 0)\n+\t\treturn 1;\n+\telse if (diff2 < 0)\n+\t\treturn -1;\n+\telse\n+\t\treturn 0;\n+}\n+\n+static void\n+bandwidth_left(int port_id, uint64_t load, uint8_t update_idx, struct bwg_slave *bwg_slave)\n+{\n+\tstruct rte_eth_link link_status;\n+\n+\trte_eth_link_get(port_id, &link_status);\n+\tuint64_t link_bwg = link_status.link_speed * 1000000ULL / 8;\n+\tif (link_bwg == 0)\n+\t\treturn;\n+\tlink_bwg = (link_bwg * (update_idx+1) * REORDER_PERIOD_MS);\n+\tbwg_slave->bwg_left_int = (link_bwg - 1000*load) / link_bwg;\n+\tbwg_slave->bwg_left_remainder = (link_bwg - 1000*load) % link_bwg;\n+}\n+\n+static void\n+bond_ethdev_update_tlb_slave_cb(void *arg)\n+{\n+\tstruct bond_dev_private *internals = arg;\n+\tstruct rte_eth_stats slave_stats;\n+\tstruct bwg_slave bwg_array[RTE_MAX_ETHPORTS];\n+\tuint8_t slave_count;\n+\tuint64_t tx_bytes;\n+\tuint8_t update_stats = 0;\n+\tint8_t i;\n+\n+\tinternals->slave_update_idx++;\n+\n+\n+\tif (internals->slave_update_idx >= REORDER_PERIOD_MS)\n+\t\tupdate_stats = 1;\n+\n+\tfor (i = 0; i < internals->active_slave_count; i++) {\n+\t\trte_eth_stats_get(internals->active_slaves[i], &slave_stats);\n+\t\ttx_bytes = slave_stats.obytes -\n+\t\t\t\tinternals->slaves[i].last_obytes;\n+\t\tbandwidth_left(internals->active_slaves[i], tx_bytes,\n+\t\t\t\tinternals->slave_update_idx, &bwg_array[i]);\n+\t\tbwg_array[i].slave = internals->active_slaves[i];\n+\n+\t\tif (update_stats)\n+\t\t\tinternals->slaves[i].last_obytes = slave_stats.obytes;\n+\t}\n+\n+\tif (update_stats == 1)\n+\t\tinternals->slave_update_idx = 0;\n+\n+\tslave_count = i;\n+\tqsort(bwg_array, slave_count, sizeof(bwg_array[0]), bandwidth_cmp);\n+\tfor (i = 0; i < slave_count; i++)\n+\t\tinternals->active_slaves[i] = bwg_array[i].slave;\n+\n+\trte_eal_alarm_set(REORDER_PERIOD_MS * 1000, bond_ethdev_update_tlb_slave_cb,\n+\t\t\t(struct bond_dev_private *)internals);\n+}\n+\n+static uint16_t\n+bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n+{\n+\tstruct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;\n+\tstruct bond_dev_private *internals = bd_tx_q->dev_private;\n+\n+\tstruct rte_eth_dev *primary_port = &rte_eth_devices[internals->primary_port];\n+\tuint16_t num_tx_total = 0;\n+\tuint8_t i, j;\n+\n+\tuint8_t num_of_slaves = internals->active_slave_count;\n+\tuint8_t slaves[RTE_MAX_ETHPORTS];\n+\n+\tstruct ether_hdr *ether_hdr;\n+\tstruct ether_addr primary_slave_addr;\n+\tstruct ether_addr active_slave_addr;\n+\n+\tif (num_of_slaves < 1)\n+\t\treturn num_tx_total;\n+\n+\tmemcpy(slaves, internals->active_slaves,\n+\t\t\t\tsizeof(internals->active_slaves[0]) * num_of_slaves);\n+\n+\n+\tether_addr_copy(primary_port->data->mac_addrs, &primary_slave_addr);\n+\n+\tif (nb_pkts > 3) {\n+\t\tfor (i = 0; i < 3; i++)\n+\t\t\trte_prefetch0(rte_pktmbuf_mtod(bufs[i], void*));\n+\t}\n+\n+\tfor (i = 0; i < num_of_slaves; i++) {\n+\t\tether_addr_copy(&internals->slaves[slaves[i]].persisted_mac_addr,\n+\t\t\t\t&active_slave_addr);\n+\n+\t\tfor (j = num_tx_total; j < nb_pkts; j++) {\n+\t\t\tif (j + 3 < nb_pkts)\n+\t\t\t\trte_prefetch0(rte_pktmbuf_mtod(bufs[j+3], void*));\n+\n+\t\t\tether_hdr = rte_pktmbuf_mtod(bufs[j], struct ether_hdr *);\n+\t\t\tif (is_same_ether_addr(&ether_hdr->s_addr, &primary_slave_addr))\n+\t\t\t\tether_addr_copy(&active_slave_addr, &ether_hdr->s_addr);\n+\t\t}\n+\n+\t\tnum_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,\n+\t\t\t\tbufs + num_tx_total, nb_pkts - num_tx_total);\n+\n+\t\tif (num_tx_total == nb_pkts)\n+\t\t\tbreak;\n+\t}\n+\n+\treturn num_tx_total;\n+}\n+\n static uint16_t\n bond_ethdev_tx_burst_balance(void *queue, struct rte_mbuf **bufs,\n \t\tuint16_t nb_pkts)\n@@ -495,6 +633,7 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)\n \t\t}\n \t\tbreak;\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n+\tcase BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:\n \tdefault:\n \t\tfor (i = 0; i < internals->slave_count; i++) {\n \t\t\tif (internals->slaves[i].port_id ==\n@@ -544,6 +683,10 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)\n \t\teth_dev->tx_pkt_burst = bond_ethdev_tx_burst_broadcast;\n \t\teth_dev->rx_pkt_burst = bond_ethdev_rx_burst;\n \t\tbreak;\n+\tcase BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:\n+\t\teth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb;\n+\t\teth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup;\n+\t\tbreak;\n \tdefault:\n \t\treturn -1;\n \t}\n@@ -757,6 +900,9 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)\n \t\t\t\tbond_ethdev_slave_link_status_change_monitor,\n \t\t\t\t(void *)eth_dev);\n \n+\tif (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {\n+\t\tbond_ethdev_update_tlb_slave_cb(internals);\n+\t}\n \treturn 0;\n }\n \n@@ -765,6 +911,9 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)\n {\n \tstruct bond_dev_private *internals = eth_dev->data->dev_private;\n \n+\tif (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {\n+\t\trte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, internals);\n+    }\n \tinternals->active_slave_count = 0;\n \tinternals->link_status_polling_enabled = 0;\n \n@@ -775,6 +924,12 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)\n static void\n bond_ethdev_close(struct rte_eth_dev *dev __rte_unused)\n {\n+\tstruct bond_dev_private *internals = dev->data->dev_private;\n+\n+\tif (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {\n+\t\trte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, internals);\n+\t}\n+\tinternals->active_slave_count = 0;\n }\n \n static int\n@@ -884,7 +1039,7 @@ bond_ethdev_slave_link_status_change_monitor(void *cb_arg)\n \n \t/* If device is currently being configured then don't check slaves link\n \t * status, wait until next period */\n-\tif (rte_spinlock_trylock(&internals->lock)){\n+\tif (rte_spinlock_trylock(&internals->lock)) {\n \t\tfor (i = 0; i < internals->slave_count; i++) {\n \t\t\tif (internals->slaves[i].link_status_polling_enabled) {\n \t\t\t\tslave_ethdev = &rte_eth_devices[internals->slaves[i].port_id];\n@@ -1004,6 +1159,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)\n \t\tbreak;\n \t/* Promiscuous mode is propagated only to primary slave */\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n+\tcase BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:\n \tdefault:\n \t\trte_eth_promiscuous_enable(internals->current_primary_port);\n \n@@ -1028,6 +1184,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)\n \t\tbreak;\n \t/* Promiscuous mode is propagated only to primary slave */\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n+\tcase BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:\n \tdefault:\n \t\trte_eth_promiscuous_disable(internals->current_primary_port);\n \t}\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_private.h b/lib/librte_pmd_bond/rte_eth_bond_private.h\nindex 6db5144..f7186a8 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_private.h\n+++ b/lib/librte_pmd_bond/rte_eth_bond_private.h\n@@ -89,7 +89,6 @@ struct bond_tx_queue {\n \t/**< Copy of TX configuration structure for queue */\n };\n \n-\n /** Bonded slave devices structure */\n struct bond_ethdev_slave_ports {\n \tuint8_t slaves[RTE_MAX_ETHPORTS];\t/**< Slave port id array */\n@@ -102,6 +101,7 @@ struct bond_slave_details {\n \tuint8_t link_status_polling_enabled;\n \tuint8_t link_status_wait_to_complete;\n \tuint8_t last_link_status;\n+\tuint64_t last_obytes;\n \n \t/**< Port Id of slave eth_dev */\n \tstruct ether_addr persisted_mac_addr;\n@@ -143,6 +143,7 @@ struct bond_dev_private {\n \tuint8_t slave_count;\t\t\t/**< Number of bonded slaves */\n \tstruct bond_slave_details slaves[RTE_MAX_ETHPORTS];\n \t/**< Arary of bonded slaves details */\n+\tuint8_t slave_update_idx;\n };\n \n extern struct eth_dev_ops default_dev_ops;\n",
    "prefixes": [
        "dpdk-dev",
        "v2"
    ]
}