get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 1205,
    "url": "https://patches.dpdk.org/api/patches/1205/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1415362978-6306-8-git-send-email-declan.doherty@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.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": "<1415362978-6306-8-git-send-email-declan.doherty@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1415362978-6306-8-git-send-email-declan.doherty@intel.com",
    "date": "2014-11-07T12:22:57",
    "name": "[dpdk-dev,v6,7/8] bond: lsc polling support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "cf348af0507d66c75f1a57f4bdee531e458acb6d",
    "submitter": {
        "id": 11,
        "url": "https://patches.dpdk.org/api/people/11/?format=api",
        "name": "Doherty, Declan",
        "email": "declan.doherty@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1415362978-6306-8-git-send-email-declan.doherty@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/1205/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/1205/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 14B197F58;\n\tFri,  7 Nov 2014 13:14:23 +0100 (CET)",
            "from mga09.intel.com (mga09.intel.com [134.134.136.24])\n\tby dpdk.org (Postfix) with ESMTP id 6ACE87F45\n\tfor <dev@dpdk.org>; Fri,  7 Nov 2014 13:14:13 +0100 (CET)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n\tby orsmga102.jf.intel.com with ESMTP; 07 Nov 2014 04:21:36 -0800",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga002.jf.intel.com with ESMTP; 07 Nov 2014 04:23:17 -0800",
            "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\tsA7CNFtG002857; Fri, 7 Nov 2014 12:23:15 GMT",
            "from sivswdev02.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev02.ir.intel.com with ESMTP id sA7CNFn4007663;\n\tFri, 7 Nov 2014 12:23:15 GMT",
            "(from dwdohert@localhost)\n\tby sivswdev02.ir.intel.com with  id sA7CNF4I007659;\n\tFri, 7 Nov 2014 12:23:15 GMT"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.07,332,1413270000\"; d=\"scan'208\";a=\"633260100\"",
        "From": "Declan Doherty <declan.doherty@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri,  7 Nov 2014 12:22:57 +0000",
        "Message-Id": "<1415362978-6306-8-git-send-email-declan.doherty@intel.com>",
        "X-Mailer": "git-send-email 1.7.12.2",
        "In-Reply-To": "<1415362978-6306-1-git-send-email-declan.doherty@intel.com>",
        "References": "<1413291597-27326-1-git-send-email-declan.doherty@intel.com>\n\t<1415362978-6306-1-git-send-email-declan.doherty@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v6 7/8] bond: lsc polling support",
        "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: Declan Doherty <declan.doherty@intel.com>\n---\n app/test-pmd/cmdline.c                      |  63 +++++\n app/test/test.h                             |   7 +-\n app/test/test_link_bonding.c                | 265 ++++++++++++-------\n app/test/virtual_pmd.c                      |  17 +-\n app/test/virtual_pmd.h                      |  48 +++-\n doc/guides/testpmd_app_ug/testpmd_funcs.rst |  19 ++\n lib/librte_pmd_bond/rte_eth_bond.h          |  80 ++++++\n lib/librte_pmd_bond/rte_eth_bond_api.c      | 315 ++++++++++++++--------\n lib/librte_pmd_bond/rte_eth_bond_args.c     |  28 +-\n lib/librte_pmd_bond/rte_eth_bond_pmd.c      | 393 +++++++++++++++++++++-------\n lib/librte_pmd_bond/rte_eth_bond_private.h  |  71 +++--\n 11 files changed, 958 insertions(+), 348 deletions(-)",
    "diff": "diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c\nindex be12c13..ee8c121 100644\n--- a/app/test-pmd/cmdline.c\n+++ b/app/test-pmd/cmdline.c\n@@ -462,6 +462,9 @@ static void cmd_help_long_parsed(void *parsed_result,\n \n \t\t\t\"set bonding xmit_balance_policy (port_id) (l2|l23|l34)\\n\"\n \t\t\t\"\tSet the transmit balance policy for bonded device running in balance mode.\\n\\n\"\n+\n+\t\t\t\"set bonding mon_period (port_id) (value) \\n\"\n+\t\t\t\"\tSet the bonding link status monitoring polling period in ms.\\n\\n\"\n #endif\n \n \t\t\t, list_pkt_forwarding_modes()\n@@ -3733,6 +3736,65 @@ cmdline_parse_inst_t cmd_set_bond_mac_addr = {\n \t\t}\n };\n \n+\n+/* *** SET LINK STATUS MONITORING POLLING PERIOD ON BONDED DEVICE *** */\n+struct cmd_set_bond_mon_period_result {\n+\tcmdline_fixed_string_t set;\n+\tcmdline_fixed_string_t bonding;\n+\tcmdline_fixed_string_t mon_period;\n+\tuint8_t port_num;\n+\tuint32_t period_ms;\n+};\n+\n+static void cmd_set_bond_mon_period_parsed(void *parsed_result,\n+\t\t__attribute__((unused))  struct cmdline *cl,\n+\t\t__attribute__((unused)) void *data)\n+{\n+\tstruct cmd_set_bond_mon_period_result *res = parsed_result;\n+\tint ret;\n+\n+\tif (res->port_num >= nb_ports) {\n+\t\tprintf(\"Port id %d must be less than %d\\n\", res->port_num, nb_ports);\n+\t\treturn;\n+\t}\n+\n+\tret = rte_eth_bond_link_monitoring_set(res->port_num, res->period_ms);\n+\n+\t/* check the return value and print it if is < 0 */\n+\tif (ret < 0)\n+\t\tprintf(\"set_bond_mac_addr error: (%s)\\n\", strerror(-ret));\n+}\n+\n+cmdline_parse_token_string_t cmd_set_bond_mon_period_set =\n+\t\tTOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,\n+\t\t\t\tset, \"set\");\n+cmdline_parse_token_string_t cmd_set_bond_mon_period_bonding =\n+\t\tTOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,\n+\t\t\t\tbonding, \"bonding\");\n+cmdline_parse_token_string_t cmd_set_bond_mon_period_mon_period =\n+\t\tTOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,\n+\t\t\t\tmon_period,\t\"mon_period\");\n+cmdline_parse_token_num_t cmd_set_bond_mon_period_portnum =\n+\t\tTOKEN_NUM_INITIALIZER(struct cmd_set_bond_mon_period_result,\n+\t\t\t\tport_num, UINT8);\n+cmdline_parse_token_num_t cmd_set_bond_mon_period_period_ms =\n+\t\tTOKEN_NUM_INITIALIZER(struct cmd_set_bond_mon_period_result,\n+\t\t\t\tperiod_ms, UINT32);\n+\n+cmdline_parse_inst_t cmd_set_bond_mon_period = {\n+\t\t.f = cmd_set_bond_mon_period_parsed,\n+\t\t.data = (void *) 0,\n+\t\t.help_str = \"set bonding mon_period (port_id) (period_ms): \",\n+\t\t.tokens = {\n+\t\t\t\t(void *)&cmd_set_bond_mon_period_set,\n+\t\t\t\t(void *)&cmd_set_bond_mon_period_bonding,\n+\t\t\t\t(void *)&cmd_set_bond_mon_period_mon_period,\n+\t\t\t\t(void *)&cmd_set_bond_mon_period_portnum,\n+\t\t\t\t(void *)&cmd_set_bond_mon_period_period_ms,\n+\t\t\t\tNULL\n+\t\t}\n+};\n+\n #endif /* RTE_LIBRTE_PMD_BOND */\n \n /* *** SET FORWARDING MODE *** */\n@@ -7787,6 +7849,7 @@ cmdline_parse_ctx_t main_ctx[] = {\n \t(cmdline_parse_inst_t *) &cmd_create_bonded_device,\n \t(cmdline_parse_inst_t *) &cmd_set_bond_mac_addr,\n \t(cmdline_parse_inst_t *) &cmd_set_balance_xmit_policy,\n+\t(cmdline_parse_inst_t *) &cmd_set_bond_mon_period,\n #endif\n \t(cmdline_parse_inst_t *)&cmd_vlan_offload,\n \t(cmdline_parse_inst_t *)&cmd_vlan_tpid,\ndiff --git a/app/test/test.h b/app/test/test.h\nindex 98ab804..24b1640 100644\n--- a/app/test/test.h\n+++ b/app/test/test.h\n@@ -62,14 +62,15 @@\n \n #define TEST_ASSERT_SUCCESS(val, msg, ...) do {\t\t\t\t\t\\\n \t\tif (!(val == 0)) {\t\t\t\t\t\t\t\t\t\t\\\n-\t\t\tprintf(\"TestCase %s() line %d failed: \"\t\t\t\\\n-\t\t\t\tmsg \"\\n\", __func__, __LINE__, ##__VA_ARGS__);\t\\\n+\t\t\tprintf(\"TestCase %s() line %d failed (err %d): \"\t\\\n+\t\t\t\tmsg \"\\n\", __func__, __LINE__, val,\t\t\t\t\\\n+\t\t\t\t##__VA_ARGS__);\t\t\t\t\t\t\t\t\t\\\n \t\t\treturn -1;\t\t\t\t\t\t\t\t\t\t\t\\\n \t\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n } while (0)\n \n #define TEST_ASSERT_FAIL(val, msg, ...) do {\t\t\t\t\t\\\n-\t\tif (!(val != -1)) {\t\t\t\t\t\t\t\t\t\t\\\n+\t\tif (!(val != 0)) {\t\t\t\t\t\t\t\t\t\t\\\n \t\t\tprintf(\"TestCase %s() line %d failed: \"\t\t\t\\\n \t\t\t\tmsg \"\\n\", __func__, __LINE__, ##__VA_ARGS__);\t\\\n \t\t\treturn -1;\t\t\t\t\t\t\t\t\t\t\t\\\ndiff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c\nindex 547ee78..4aa57a7 100644\n--- a/app/test/test_link_bonding.c\n+++ b/app/test/test_link_bonding.c\n@@ -234,42 +234,34 @@ configure_ethdev(uint8_t port_id, uint8_t start, uint8_t en_isr)\n \telse\n \t\tdefault_pmd_conf.intr_conf.lsc = 0;\n \n-\tif (rte_eth_dev_configure(port_id, test_params->nb_rx_q,\n-\t\t\ttest_params->nb_tx_q, &default_pmd_conf) != 0) {\n-\t\tgoto error;\n-\t}\n+\tTEST_ASSERT_SUCCESS(rte_eth_dev_configure(port_id, test_params->nb_rx_q,\n+\t\t\ttest_params->nb_tx_q, &default_pmd_conf),\n+\t\t\t\"rte_eth_dev_configure for port %d failed\", port_id);\n \n-\tfor (q_id = 0; q_id < test_params->nb_rx_q; q_id++) {\n-\t\tif (rte_eth_rx_queue_setup(port_id, q_id, RX_RING_SIZE,\n+\tfor (q_id = 0; q_id < test_params->nb_rx_q; q_id++)\n+\t\tTEST_ASSERT_SUCCESS(rte_eth_rx_queue_setup(port_id, q_id, RX_RING_SIZE,\n \t\t\t\trte_eth_dev_socket_id(port_id), &rx_conf_default,\n-\t\t\t\ttest_params->mbuf_pool) < 0) {\n-\t\t\tgoto error;\n-\t\t}\n-\t}\n+\t\t\t\ttest_params->mbuf_pool) ,\n+\t\t\t\t\"rte_eth_rx_queue_setup for port %d failed\", port_id);\n \n-\tfor (q_id = 0; q_id < test_params->nb_tx_q; q_id++) {\n-\t\tif (rte_eth_tx_queue_setup(port_id, q_id, TX_RING_SIZE,\n-\t\t\t\trte_eth_dev_socket_id(port_id), &tx_conf_default) < 0) {\n-\t\t\tprintf(\"Failed to setup tx queue (%d).\\n\", q_id);\n-\t\t\tgoto error;\n-\t\t}\n-\t}\n+\tfor (q_id = 0; q_id < test_params->nb_tx_q; q_id++)\n+\t\tTEST_ASSERT_SUCCESS(rte_eth_tx_queue_setup(port_id, q_id, TX_RING_SIZE,\n+\t\t\t\trte_eth_dev_socket_id(port_id), &tx_conf_default),\n+\t\t\t\t\"rte_eth_tx_queue_setup for port %d failed\", port_id);\n \n-\tif (start) {\n-\t\tif (rte_eth_dev_start(port_id) < 0) {\n-\t\t\tprintf(\"Failed to start device (%d).\\n\", port_id);\n-\t\t\tgoto error;\n-\t\t}\n-\t}\n-\treturn 0;\n+\tif (start)\n+\t\tTEST_ASSERT_SUCCESS(rte_eth_dev_start(port_id),\n+\t\t\t\t\"rte_eth_dev_start for port %d failed\", port_id);\n \n-error:\n-\tprintf(\"Failed to configure ethdev %d\\n\", port_id);\n-\treturn -1;\n+\treturn 0;\n }\n \n static int slaves_initialized;\n \n+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;\n+static pthread_cond_t cvar = PTHREAD_COND_INITIALIZER;\n+\n+\n static int\n test_setup(void)\n {\n@@ -310,7 +302,7 @@ test_setup(void)\n \t\t\tsnprintf(pmd_name, RTE_ETH_NAME_MAX_LEN, \"eth_virt_%d\", i);\n \n \t\t\ttest_params->slave_port_ids[i] = virtual_ethdev_create(pmd_name,\n-\t\t\t\t\tmac_addr, rte_socket_id());\n+\t\t\t\t\tmac_addr, rte_socket_id(), 1);\n \t\t\tif (test_params->slave_port_ids[i] < 0) {\n \t\t\t\tprintf(\"Failed to create virtual virtual ethdev %s\\n\", pmd_name);\n \t\t\t\treturn -1;\n@@ -414,34 +406,27 @@ test_create_bonded_device_with_invalid_params(void)\n static int\n test_add_slave_to_bonded_device(void)\n {\n-\tint retval, current_slave_count;\n+\tint current_slave_count;\n \n \tuint8_t slaves[RTE_MAX_ETHPORTS];\n \n-\tretval = rte_eth_bond_slave_add(test_params->bonded_port_id,\n-\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count]);\n-\tif (retval != 0) {\n-\t\tprintf(\"Failed to add slave (%d) to bonded port (%d).\\n\",\n-\t\t\t\ttest_params->bonded_port_id,\n-\t\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count]);\n-\t\treturn -1;\n-\t}\n+\tTEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id,\n+\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count]),\n+\t\t\t\"Failed to add slave (%d) to bonded port (%d).\",\n+\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count],\n+\t\t\ttest_params->bonded_port_id);\n \n \tcurrent_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,\n \t\t\tslaves, RTE_MAX_ETHPORTS);\n-\tif (current_slave_count != test_params->bonded_slave_count + 1) {\n-\t\tprintf(\"Number of slaves (%d) is greater than expected (%d).\\n\",\n-\t\t\t\tcurrent_slave_count, test_params->bonded_slave_count + 1);\n-\t\treturn -1;\n-\t}\n+\tTEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count + 1,\n+\t\t\t\"Number of slaves (%d) is greater than expected (%d).\",\n+\t\t\tcurrent_slave_count, test_params->bonded_slave_count + 1);\n \n \tcurrent_slave_count = rte_eth_bond_active_slaves_get(\n \t\t\ttest_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS);\n-\tif (current_slave_count != 0) {\n-\t\tprintf(\"Number of active slaves (%d) is not as expected (%d).\\n\",\n-\t\t\t\tcurrent_slave_count, 0);\n-\t\treturn -1;\n-\t}\n+\tTEST_ASSERT_EQUAL(current_slave_count, 0,\n+\t\t\t\t\t\"Number of active slaves (%d) is not as expected (%d).\\n\",\n+\t\t\t\t\tcurrent_slave_count, 0);\n \n \ttest_params->bonded_slave_count++;\n \n@@ -476,27 +461,23 @@ test_add_slave_to_invalid_bonded_device(void)\n static int\n test_remove_slave_from_bonded_device(void)\n {\n-\tint retval, current_slave_count;\n+\tint current_slave_count;\n \tstruct ether_addr read_mac_addr, *mac_addr;\n \tuint8_t slaves[RTE_MAX_ETHPORTS];\n \n-\tretval = rte_eth_bond_slave_remove(test_params->bonded_port_id,\n-\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count-1]);\n-\tif (retval != 0) {\n-\t\tprintf(\"\\t Failed to remove slave %d from bonded port (%d).\\n\",\n-\t\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count-1],\n-\t\t\t\ttest_params->bonded_port_id);\n-\t\treturn -1;\n-\t}\n+\tTEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(test_params->bonded_port_id,\n+\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count-1]),\n+\t\t\t\"Failed to remove slave %d from bonded port (%d).\",\n+\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count-1],\n+\t\t\ttest_params->bonded_port_id);\n \n \n \tcurrent_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,\n \t\t\tslaves, RTE_MAX_ETHPORTS);\n-\tif (current_slave_count != test_params->bonded_slave_count - 1) {\n-\t\tprintf(\"Number of slaves (%d) is great than expected (%d).\\n\",\n-\t\t\t\tcurrent_slave_count, 0);\n-\t\treturn -1;\n-\t}\n+\n+\tTEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count - 1,\n+\t\t\t\"Number of slaves (%d) is great than expected (%d).\\n\",\n+\t\t\tcurrent_slave_count, test_params->bonded_slave_count - 1);\n \n \n \tmac_addr = (struct ether_addr *)slave_mac;\n@@ -506,10 +487,8 @@ test_remove_slave_from_bonded_device(void)\n \trte_eth_macaddr_get(\n \t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count-1],\n \t\t\t&read_mac_addr);\n-\tif (memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {\n-\t\tprintf(\"bonded port mac address not set to that of primary port\\n\");\n-\t\treturn -1;\n-\t}\n+\tTEST_ASSERT_SUCCESS(memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr)),\n+\t\t\t\"bonded port mac address not set to that of primary port\\n\");\n \n \trte_eth_stats_reset(\n \t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count-1]);\n@@ -891,21 +870,20 @@ test_set_primary_slave(void)\n \t\treturn -1;\n \t}\n \n+\t/* Non bonded device */\n+\tretval = rte_eth_bond_primary_set(test_params->slave_port_ids[i],\n+\t\t\ttest_params->slave_port_ids[i]);\n+\tif (retval == 0) {\n+\t\tprintf(\"Expected call to failed as invalid port specified.\\n\");\n+\t\treturn -1;\n+\t}\n+\n \t/* Set slave as primary\n \t * Verify slave it is now primary slave\n \t * Verify that MAC address of bonded device is that of primary slave\n \t * Verify that MAC address of all bonded slaves are that of primary slave\n \t */\n \tfor (i = 0; i < 4; i++) {\n-\n-\t\t/* Non bonded device */\n-\t\tretval = rte_eth_bond_primary_set(test_params->slave_port_ids[i],\n-\t\t\t\ttest_params->slave_port_ids[i]);\n-\t\tif (retval == 0) {\n-\t\t\tprintf(\"Expected call to failed as invalid port specified.\\n\");\n-\t\t\treturn -1;\n-\t\t}\n-\n \t\tretval = rte_eth_bond_primary_set(test_params->bonded_port_id,\n \t\t\t\ttest_params->slave_port_ids[i]);\n \t\tif (retval != 0) {\n@@ -929,6 +907,7 @@ test_set_primary_slave(void)\n \n \t\t/* stop/start bonded eth dev to apply new MAC */\n \t\trte_eth_dev_stop(test_params->bonded_port_id);\n+\n \t\tif (rte_eth_dev_start(test_params->bonded_port_id) != 0)\n \t\t\treturn -1;\n \n@@ -1093,19 +1072,18 @@ static int\n initialize_bonded_device_with_slaves(uint8_t bonding_mode, uint8_t bond_en_isr,\n \t\tuint8_t number_of_slaves, uint8_t enable_slave)\n {\n-\t/* configure bonded device */\n+\t/* Configure bonded device */\n \tTEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 0,\n \t\t\tbond_en_isr), \"Failed to configure bonding port (%d) in mode %d \"\n \t\t\t\"with (%d) slaves.\", test_params->bonded_port_id, bonding_mode,\n \t\t\tnumber_of_slaves);\n \n-\twhile (number_of_slaves > test_params->bonded_slave_count) {\n-\t\t/* Add slaves to bonded device */\n+\t/* Add slaves to bonded device */\n+\twhile (number_of_slaves > test_params->bonded_slave_count)\n \t\tTEST_ASSERT_SUCCESS(test_add_slave_to_bonded_device(),\n \t\t\t\t\"Failed to add slave (%d to  bonding port (%d).\",\n \t\t\t\ttest_params->bonded_slave_count - 1,\n \t\t\t\ttest_params->bonded_port_id);\n-\t}\n \n \t/* Set link bonding mode  */\n \tTEST_ASSERT_SUCCESS(rte_eth_bond_mode_set(test_params->bonded_port_id,\n@@ -1128,9 +1106,9 @@ test_adding_slave_after_bonded_device_started(void)\n {\n \tint i;\n \n-\tif (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 0, 4, 0)\n-\t\t\t!= 0)\n-\t\treturn -1;\n+\tTEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(\n+\t\t\tBONDING_MODE_ROUND_ROBIN, 0, 4, 0),\n+\t\t\t\"Failed to add slaves to bonded device\");\n \n \t/* Enabled slave devices */\n \tfor (i = 0; i < test_params->bonded_slave_count + 1; i++) {\n@@ -1138,12 +1116,9 @@ test_adding_slave_after_bonded_device_started(void)\n \t\t\t\ttest_params->slave_port_ids[i], 1);\n \t}\n \n-\tif (rte_eth_bond_slave_add(test_params->bonded_port_id,\n-\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count]) !=\n-\t\t\t\t\t0) {\n-\t\tprintf(\"\\t Failed to add slave to bonded port.\\n\");\n-\t\treturn -1;\n-\t}\n+\tTEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id,\n+\t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count]),\n+\t\t\t\"Failed to add slave to bonded port.\\n\");\n \n \trte_eth_stats_reset(\n \t\t\ttest_params->slave_port_ids[test_params->bonded_slave_count]);\n@@ -1158,8 +1133,6 @@ test_adding_slave_after_bonded_device_started(void)\n \n int test_lsc_interupt_count;\n \n-static pthread_mutex_t mutex;\n-static pthread_cond_t cvar;\n \n static void\n test_bonding_lsc_event_callback(uint8_t port_id __rte_unused,\n@@ -1183,7 +1156,7 @@ lsc_timeout(int wait_us)\n \tgettimeofday(&tp, NULL);\n \n \t/* Convert from timeval to timespec */\n-\tts.tv_sec  = tp.tv_sec;\n+\tts.tv_sec = tp.tv_sec;\n \tts.tv_nsec = tp.tv_usec * 1000;\n \tts.tv_nsec += wait_us * 1000;\n \n@@ -1193,6 +1166,9 @@ lsc_timeout(int wait_us)\n \n \tpthread_mutex_unlock(&mutex);\n \n+\tif (retval == 0 && test_lsc_interupt_count < 1)\n+\t\treturn -1;\n+\n \treturn retval;\n }\n \n@@ -1202,9 +1178,6 @@ test_status_interrupt(void)\n \tint slave_count;\n \tuint8_t slaves[RTE_MAX_ETHPORTS];\n \n-\tpthread_mutex_init(&mutex, NULL);\n-\tpthread_cond_init(&cvar, NULL);\n-\n \t/* initialized bonding device with T slaves */\n \tif (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 1,\n \t\t\tTEST_STATUS_INTERRUPT_SLAVE_COUNT, 1) != 0)\n@@ -1284,9 +1257,6 @@ test_status_interrupt(void)\n \t\t\t\tRTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback,\n \t\t\t\t&test_params->bonded_port_id);\n \n-\tpthread_mutex_destroy(&mutex);\n-\tpthread_cond_destroy(&cvar);\n-\n \t/* Clean up and remove slaves from bonded device */\n \treturn remove_slaves_and_stop_bonded_device();\n }\n@@ -1419,6 +1389,7 @@ test_roundrobin_tx_burst(void)\n \treturn remove_slaves_and_stop_bonded_device();\n }\n \n+#ifdef RTE_MBUF_REFCNT\n static int\n verify_mbufs_ref_count(struct rte_mbuf **mbufs, int nb_mbufs, int val)\n {\n@@ -1432,6 +1403,7 @@ verify_mbufs_ref_count(struct rte_mbuf **mbufs, int nb_mbufs, int val)\n \t}\n \treturn 0;\n }\n+#endif\n \n \n static void\n@@ -1537,11 +1509,12 @@ test_roundrobin_tx_burst_slave_tx_fail(void)\n \t\t\t\t(unsigned int)port_stats.opackets, slave_expected_tx_count);\n \t}\n \n+#ifdef RTE_MBUF_REFCNT\n \t/* Verify that all mbufs have a ref value of zero */\n \tTEST_ASSERT_SUCCESS(verify_mbufs_ref_count(&pkt_burst[tx_count],\n \t\t\tTEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT, 1),\n \t\t\t\"mbufs refcnts not as expected\");\n-\n+#endif\n \tfree_mbufs(&pkt_burst[tx_count], TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT);\n \n \t/* Clean up and remove slaves from bonded device */\n@@ -2028,6 +2001,101 @@ test_roundrobin_verify_slave_link_status_change_behaviour(void)\n \treturn remove_slaves_and_stop_bonded_device();\n }\n \n+#define TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT (2)\n+\n+uint8_t polling_slave_mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00 };\n+\n+#include \"unistd.h\"\n+\n+int polling_test_slaves[TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT] = { -1, -1 } ;\n+\n+static int\n+test_roundrobin_verfiy_polling_slave_link_status_change(void)\n+{\n+\tstruct ether_addr *mac_addr = (struct ether_addr *)polling_slave_mac;\n+\tchar slave_name[RTE_ETH_NAME_MAX_LEN];\n+\n+\tint i;\n+\n+\tfor (i = 0; i < TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT; i++) {\n+\t\t/* Generate slave name / MAC address */\n+\t\tsnprintf(slave_name, RTE_ETH_NAME_MAX_LEN, \"eth_virt_poll_%d\", i);\n+\t\tmac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i;\n+\n+\t\t/* Create slave devices with no ISR Support */\n+\t\tif (polling_test_slaves[i] == -1) {\n+\t\t\tpolling_test_slaves[i] = virtual_ethdev_create(slave_name, mac_addr,\n+\t\t\t\t\trte_socket_id(), 0);\n+\t\t\tTEST_ASSERT(polling_test_slaves[i] >= 0,\n+\t\t\t\t\t\"Failed to create virtual virtual ethdev %s\\n\", slave_name);\n+\n+\t\t\t/* Configure slave */\n+\t\t\tTEST_ASSERT_SUCCESS(configure_ethdev(polling_test_slaves[i], 0, 0),\n+\t\t\t\t\t\"Failed to configure virtual ethdev %s(%d)\", slave_name,\n+\t\t\t\t\tpolling_test_slaves[i]);\n+\t\t}\n+\n+\t\t/* Add slave to bonded device */\n+\t\tTEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id,\n+\t\t\t\tpolling_test_slaves[i]),\n+\t\t\t\t\"Failed to add slave %s(%d) to bonded device %d\",\n+\t\t\t\tslave_name, polling_test_slaves[i], test_params->bonded_port_id);\n+\t}\n+\n+\t/* Initialize bonded device */\n+\tTEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 1, 1),\n+\t\t\t\"Failed to configure bonded device %d\",\n+\t\t\ttest_params->bonded_port_id);\n+\n+\n+\t/* Register link status change interrupt callback */\n+\trte_eth_dev_callback_register(test_params->bonded_port_id,\n+\t\t\tRTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback,\n+\t\t\t&test_params->bonded_port_id);\n+\n+\t/* link status change callback for first slave link up */\n+\ttest_lsc_interupt_count = 0;\n+\n+\tvirtual_ethdev_set_link_status(polling_test_slaves[0], 1);\n+\n+\tTEST_ASSERT_SUCCESS(lsc_timeout(15000), \"timed out waiting for interrupt\");\n+\n+\n+\t/* no link status change callback for second slave link up */\n+\ttest_lsc_interupt_count = 0;\n+\n+\tvirtual_ethdev_set_link_status(polling_test_slaves[1], 1);\n+\n+\tTEST_ASSERT_FAIL(lsc_timeout(15000), \"unexpectedly succeeded\");\n+\n+\t/* link status change callback for both slave links down */\n+\ttest_lsc_interupt_count = 0;\n+\n+\tvirtual_ethdev_set_link_status(polling_test_slaves[0], 0);\n+\tvirtual_ethdev_set_link_status(polling_test_slaves[1], 0);\n+\n+\tTEST_ASSERT_SUCCESS(lsc_timeout(20000), \"timed out waiting for interrupt\");\n+\n+\t/* Un-Register link status change interrupt callback */\n+\trte_eth_dev_callback_unregister(test_params->bonded_port_id,\n+\t\t\tRTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback,\n+\t\t\t&test_params->bonded_port_id);\n+\n+\n+\t/* Clean up and remove slaves from bonded device */\n+\tfor (i = 0; i < TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT; i++) {\n+\n+\t\tTEST_ASSERT_SUCCESS(\n+\t\t\t\trte_eth_bond_slave_remove(test_params->bonded_port_id,\n+\t\t\t\t\t\tpolling_test_slaves[i]),\n+\t\t\t\t\"Failed to remove slave %d from bonded port (%d)\",\n+\t\t\t\tpolling_test_slaves[i], test_params->bonded_port_id);\n+\t}\n+\n+\treturn remove_slaves_and_stop_bonded_device();\n+}\n+\n+\n /** Active Backup Mode Tests */\n \n static int\n@@ -3161,10 +3229,12 @@ test_balance_tx_burst_slave_tx_fail(void)\n \t\t\t\t(unsigned int)port_stats.opackets,\n \t\t\t\tTEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2);\n \n+#ifdef RTE_MBUF_REFCNT\n \t/* Verify that all mbufs have a ref value of zero */\n \tTEST_ASSERT_SUCCESS(verify_mbufs_ref_count(&pkts_burst_1[tx_count_1],\n \t\t\tTEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT, 1),\n \t\t\t\"mbufs refcnts not as expected\");\n+#endif\n \n \tfree_mbufs(&pkts_burst_1[tx_count_1],\n \t\t\tTEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT);\n@@ -4316,6 +4386,7 @@ static struct unit_test_suite link_bonding_test_suite  = {\n \t\tTEST_CASE(test_roundrobin_verify_promiscuous_enable_disable),\n \t\tTEST_CASE(test_roundrobin_verify_mac_assignment),\n \t\tTEST_CASE(test_roundrobin_verify_slave_link_status_change_behaviour),\n+\t\tTEST_CASE(test_roundrobin_verfiy_polling_slave_link_status_change),\n \t\tTEST_CASE(test_activebackup_tx_burst),\n \t\tTEST_CASE(test_activebackup_rx_burst),\n \t\tTEST_CASE(test_activebackup_verify_promiscuous_enable_disable),\ndiff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c\nindex 72f527e..e105c84 100644\n--- a/app/test/virtual_pmd.c\n+++ b/app/test/virtual_pmd.c\n@@ -457,6 +457,14 @@ virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id,\n }\n \n void\n+virtual_ethdev_set_link_status(uint8_t port_id, uint8_t link_status)\n+{\n+\tstruct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];\n+\n+\tvrtl_eth_dev->data->dev_link.link_status = link_status;\n+}\n+\n+void\n virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,\n \t\tuint8_t link_status)\n {\n@@ -504,7 +512,7 @@ get_number_of_sockets(void)\n \n int\n virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,\n-\t\tuint8_t socket_id)\n+\t\tuint8_t socket_id, uint8_t isr_support)\n {\n \tstruct rte_pci_device *pci_dev = NULL;\n \tstruct rte_eth_dev *eth_dev = NULL;\n@@ -554,7 +562,12 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,\n \tpci_dev->numa_node = socket_id;\n \tpci_drv->name = virtual_ethdev_driver_name;\n \tpci_drv->id_table = id_table;\n-\tpci_drv->drv_flags = RTE_PCI_DRV_INTR_LSC;\n+\n+\tif (isr_support)\n+\t\tpci_drv->drv_flags |= RTE_PCI_DRV_INTR_LSC;\n+\telse\n+\t\tpci_drv->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;\n+\n \n \teth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);\n \teth_dev->driver = eth_drv;\ndiff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h\nindex 3b5c911..2462853 100644\n--- a/app/test/virtual_pmd.h\n+++ b/app/test/virtual_pmd.h\n@@ -40,38 +40,58 @@ extern \"C\" {\n \n #include <rte_ether.h>\n \n-int virtual_ethdev_init(void);\n+int\n+virtual_ethdev_init(void);\n \n-int virtual_ethdev_create(const char *name, struct ether_addr *mac_addr, uint8_t socket_id);\n+int\n+virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,\n+\t\tuint8_t socket_id, uint8_t isr_support);\n \n-void virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id, uint8_t link_status);\n+void\n+virtual_ethdev_set_link_status(uint8_t port_id, uint8_t link_status);\n \n-void virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id, struct rte_mbuf **pkts_burst, int burst_length);\n+void\n+virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,\n+\t\tuint8_t link_status);\n \n+void\n+virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id,\n+\t\tstruct rte_mbuf **pkts_burst, int burst_length);\n \n-/** Control methods for the dev_ops functions pointer to control the behavior of the Virtual PMD */\n \n-void virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success);\n+/** Control methods for the dev_ops functions pointer to control the behavior\n+ *  of the Virtual PMD */\n \n-void virtual_ethdev_stop_fn_set_success(uint8_t port_id, uint8_t success);\n+void\n+virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success);\n \n-void virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success);\n+void\n+virtual_ethdev_stop_fn_set_success(uint8_t port_id, uint8_t success);\n \n-void virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);\n+void\n+virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success);\n \n-void virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);\n+void\n+virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);\n \n-void virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success);\n+void\n+virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);\n \n-void virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success);\n+void\n+virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success);\n \n-void virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success);\n+void\n+virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success);\n+\n+void\n+virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success);\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+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 #ifdef __cplusplus\ndiff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\nindex c0d0033..394f4bf 100755\n--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n@@ -1479,6 +1479,25 @@ For example, set a Link Bonding device (port 10) to use a balance policy of laye\n \n     testpmd> set bonding xmit_balance_policy 10 l34\n \n+\n+set bonding mon_period\n+~~~~~~~~~~~~~~~~~~~~~~\n+\n+Set the link status monitoring polling period in milliseconds for a bonding devicie.\n+\n+This adds support for PMD slave devices which do not support link status interrupts.\n+When the mon_period is set to a value greater than 0 then all PMD's which do not support\n+link status ISR will be queried every polling interval to check if their link status has changed.\n+\n+set bonding mon_period (port_id) (value)\n+\n+For example, to set the link status monitoring polling period of bonded device (port 5) to 150ms\n+\n+.. code-block:: console\n+\n+    testpmd> set bonding mon_period 5 150\n+\n+ \n show bonding config\n ~~~~~~~~~~~~~~~~~~~\n \ndiff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h\nindex 344ca1e..2ed4f7c 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond.h\n+++ b/lib/librte_pmd_bond/rte_eth_bond.h\n@@ -249,6 +249,86 @@ rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy);\n int\n rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id);\n \n+/**\n+ * Set the link monitoring frequency (in ms) for monitoring the link status of\n+ * slave devices\n+ *\n+ * @param bonded_port_id\tPort ID of bonded device.\n+ * @param internal_ms\t\tMonitoring interval in milliseconds\n+ *\n+ * @return\n+ *\t0 on success, negative value otherwise.\n+ */\n+\n+int\n+rte_eth_bond_link_monitoring_set(uint8_t bonded_port_id, uint32_t internal_ms);\n+\n+/**\n+ * Get the current link monitoring frequency (in ms) for monitoring of the link\n+ * status of slave devices\n+ *\n+ * @param bonded_port_id\tPort ID of bonded device.\n+ *\n+ * @return\n+ *\tMonitoring interval on success, negative value otherwise.\n+ */\n+int\n+rte_eth_bond_link_monitoring_get(uint8_t bonded_port_id);\n+\n+\n+/**\n+ * Set the period in milliseconds for delaying the disabling of a bonded link\n+ * when the link down status has been detected\n+ *\n+ * @param bonded_port_id\tPort ID of bonded device.\n+ * @param delay_ms\t\t\tDelay period in milliseconds.\n+ *\n+ * @return\n+ *  0 on success, negative value otherwise.\n+ */\n+int\n+rte_eth_bond_link_down_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms);\n+\n+/**\n+ * Get the period in milliseconds set for delaying the disabling of a bonded\n+ * link when the link down status has been detected\n+ *\n+ * @param bonded_port_id\tPort ID of bonded device.\n+ * @param delay_ms\t\t\tDelay period in milliseconds.\n+ *\n+ * @return\n+ *  Delay period on success, negative value otherwise.\n+ */\n+int\n+rte_eth_bond_link_down_prop_delay_get(uint8_t bonded_port_id);\n+\n+/**\n+ * Set the period in milliseconds for delaying the enabling of a bonded link\n+ * when the link up status has been detected\n+ *\n+ * @param bonded_port_id\tPort ID of bonded device.\n+ * @param delay_ms\t\t\tDelay period in milliseconds.\n+ *\n+ * @return\n+ *  0 on success, negative value otherwise.\n+ */\n+int\n+rte_eth_bond_link_up_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms);\n+\n+/**\n+ * Get the period in milliseconds set for delaying the enabling of a bonded\n+ * link when the link up status has been detected\n+ *\n+ * @param bonded_port_id\tPort ID of bonded device.\n+ * @param delay_ms\t\t\tDelay period in milliseconds.\n+ *\n+ * @return\n+ *  Delay period on success, negative value otherwise.\n+ */\n+int\n+rte_eth_bond_link_up_prop_delay_get(uint8_t bonded_port_id);\n+\n+\n #ifdef __cplusplus\n }\n #endif\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c\nindex dd33119..f146bda 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_api.c\n+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c\n@@ -39,6 +39,8 @@\n #include \"rte_eth_bond.h\"\n #include \"rte_eth_bond_private.h\"\n \n+#define DEFAULT_POLLING_INTERVAL_10_MS (10)\n+\n int\n valid_bonded_ethdev(struct rte_eth_dev *eth_dev)\n {\n@@ -63,9 +65,8 @@ valid_port_id(uint8_t port_id)\n \t/* Verify that port id is valid */\n \tint ethdev_count = rte_eth_dev_count();\n \tif (port_id >= ethdev_count) {\n-\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\"%s: port Id %d is greater than rte_eth_dev_count %d\\n\",\n-\t\t\t\t__func__, port_id, ethdev_count);\n+\t\tRTE_BOND_LOG(ERR, \"Port Id %d is greater than rte_eth_dev_count %d\",\n+\t\t\t\tport_id, ethdev_count);\n \t\treturn -1;\n \t}\n \n@@ -81,9 +82,8 @@ valid_bonded_port_id(uint8_t port_id)\n \n \t/* Verify that bonded_port_id refers to a bonded port */\n \tif (valid_bonded_ethdev(&rte_eth_devices[port_id])) {\n-\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\"%s: Specified port Id %d is not a bonded eth_dev device\\n\",\n-\t\t\t\t__func__, port_id);\n+\t\tRTE_BOND_LOG(ERR, \"Specified port Id %d is not a bonded eth_dev device\",\n+\t\t\t\tport_id);\n \t\treturn -1;\n \t}\n \n@@ -136,37 +136,36 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)\n \t */\n \n \tif (name == NULL) {\n-\t\tRTE_LOG(ERR, PMD, \"Invalid name specified\\n\");\n+\t\tRTE_BOND_LOG(ERR, \"Invalid name specified\");\n \t\tgoto err;\n \t}\n \n \tif (socket_id >= number_of_sockets()) {\n-\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\"%s: invalid socket id specified to create bonded device on.\\n\",\n-\t\t\t\t__func__);\n+\t\tRTE_BOND_LOG(ERR,\n+\t\t\t\t\"Invalid socket id specified to create bonded device on.\");\n \t\tgoto err;\n \t}\n \n \tpci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, socket_id);\n \tif (pci_dev == NULL) {\n-\t\tRTE_LOG(ERR, PMD, \"Unable to malloc pci dev on socket\\n\");\n+\t\tRTE_BOND_LOG(ERR, \"Unable to malloc pci dev on socket\");\n \t\tgoto err;\n \t}\n \n \teth_drv = rte_zmalloc_socket(name, sizeof(*eth_drv), 0, socket_id);\n \tif (eth_drv == NULL) {\n-\t\tRTE_LOG(ERR, PMD, \"Unable to malloc eth_drv on socket\\n\");\n+\t\tRTE_BOND_LOG(ERR, \"Unable to malloc eth_drv on socket\");\n \t\tgoto err;\n \t}\n \n \tpci_drv = rte_zmalloc_socket(name, sizeof(*pci_drv), 0, socket_id);\n \tif (pci_drv == NULL) {\n-\t\tRTE_LOG(ERR, PMD, \"Unable to malloc pci_drv on socket\\n\");\n+\t\tRTE_BOND_LOG(ERR, \"Unable to malloc pci_drv on socket\");\n \t\tgoto err;\n \t}\n \tpci_id_table = rte_zmalloc_socket(name, sizeof(*pci_id_table), 0, socket_id);\n \tif (pci_drv == NULL) {\n-\t\tRTE_LOG(ERR, PMD, \"Unable to malloc pci_id_table on socket\\n\");\n+\t\tRTE_BOND_LOG(ERR, \"Unable to malloc pci_id_table on socket\");\n \t\tgoto err;\n \t}\n \n@@ -181,14 +180,14 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)\n \n \tinternals = rte_zmalloc_socket(name, sizeof(*internals), 0, socket_id);\n \tif (internals == NULL) {\n-\t\tRTE_LOG(ERR, PMD, \"Unable to malloc internals on socket\\n\");\n+\t\tRTE_BOND_LOG(ERR, \"Unable to malloc internals on socket\");\n \t\tgoto err;\n \t}\n \n \t/* reserve an ethdev entry */\n \teth_dev = rte_eth_dev_allocate(name);\n \tif (eth_dev == NULL) {\n-\t\tRTE_LOG(ERR, PMD, \"Unable to allocate rte_eth_dev\\n\");\n+\t\tRTE_BOND_LOG(ERR, \"Unable to allocate rte_eth_dev\");\n \t\tgoto err;\n \t}\n \n@@ -218,25 +217,31 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)\n \teth_dev->pci_dev = pci_dev;\n \n \tif (bond_ethdev_mode_set(eth_dev, mode)) {\n-\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\"%s: failed to set bonded device %d mode too %d\\n\",\n-\t\t\t\t__func__, eth_dev->data->port_id, mode);\n+\t\tRTE_BOND_LOG(ERR, \"Failed to set bonded device %d mode too %d\",\n+\t\t\t\t eth_dev->data->port_id, mode);\n \t\tgoto err;\n \t}\n \n+\trte_spinlock_init(&internals->lock);\n+\n+\tinternals->port_id = eth_dev->data->port_id;\n \tinternals->current_primary_port = 0;\n \tinternals->balance_xmit_policy = BALANCE_XMIT_POLICY_LAYER2;\n \tinternals->user_defined_mac = 0;\n \tinternals->link_props_set = 0;\n+\n+\tinternals->link_status_polling_enabled = 0;\n+\n+\tinternals->link_status_polling_interval_ms = DEFAULT_POLLING_INTERVAL_10_MS;\n+\tinternals->link_down_delay_ms = 0;\n+\tinternals->link_up_delay_ms = 0;\n+\n \tinternals->slave_count = 0;\n \tinternals->active_slave_count = 0;\n \n \tmemset(internals->active_slaves, 0, sizeof(internals->active_slaves));\n \tmemset(internals->slaves, 0, sizeof(internals->slaves));\n \n-\tmemset(internals->presisted_slaves_conf, 0,\n-\t\t\tsizeof(internals->presisted_slaves_conf));\n-\n \treturn eth_dev->data->port_id;\n \n err:\n@@ -253,8 +258,8 @@ err:\n \treturn -1;\n }\n \n-int\n-rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)\n+static int\n+__eth_bond_slave_add_lock_free(uint8_t bonded_port_id, uint8_t slave_port_id)\n {\n \tstruct rte_eth_dev *bonded_eth_dev, *slave_eth_dev;\n \tstruct bond_dev_private *internals;\n@@ -263,56 +268,43 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)\n \n \tint i, j;\n \n-\t/* Verify that port id's are valid bonded and slave ports */\n-\tif (valid_bonded_port_id(bonded_port_id) != 0)\n-\t\tgoto err_add;\n-\n \tif (valid_slave_port_id(slave_port_id) != 0)\n-\t\tgoto err_add;\n+\t\treturn -1;\n+\n+\tbonded_eth_dev = &rte_eth_devices[bonded_port_id];\n+\tinternals = bonded_eth_dev->data->dev_private;\n \n-\t/*\n-\t * Verify that new slave device is not already a slave of another bonded\n-\t * device */\n+\t/* Verify that new slave device is not already a slave of another\n+\t * bonded device */\n \tfor (i = rte_eth_dev_count()-1; i >= 0; i--) {\n \t\tif (valid_bonded_ethdev(&rte_eth_devices[i]) == 0) {\n \t\t\ttemp_internals = rte_eth_devices[i].data->dev_private;\n+\n \t\t\tfor (j = 0; j < temp_internals->slave_count; j++) {\n \t\t\t\t/* Device already a slave of a bonded device */\n-\t\t\t\tif (temp_internals->slaves[j] == slave_port_id)\n-\t\t\t\t\tgoto err_add;\n+\t\t\t\tif (temp_internals->slaves[j].port_id == slave_port_id) {\n+\t\t\t\t\tRTE_BOND_LOG(ERR, \"Slave port %d is already a slave\",\n+\t\t\t\t\t\t\tslave_port_id);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n \t\t\t}\n \t\t}\n \t}\n \n-\tbonded_eth_dev = &rte_eth_devices[bonded_port_id];\n-\tinternals = bonded_eth_dev->data->dev_private;\n-\n \tslave_eth_dev = &rte_eth_devices[slave_port_id];\n \n-\tif (internals->slave_count > 0) {\n-\t\t/* Check that new slave device is the same type as the other slaves\n-\t\t * and not repetitive */\n-\t\tfor (i = 0; i < internals->slave_count; i++) {\n-\t\t\tif (slave_eth_dev->pci_dev->driver->id_table->device_id !=\n-\t\t\t\t\trte_eth_devices[internals->slaves[i]].pci_dev->driver->id_table->device_id ||\n-\t\t\t\tinternals->slaves[i] == slave_port_id)\n-\t\t\t\tgoto err_add;\n-\t\t}\n-\t}\n-\n \t/* Add slave details to bonded device */\n-\tinternals->slaves[internals->slave_count] = slave_port_id;\n-\n-\tslave_config_store(internals, slave_eth_dev);\n+\tslave_add(internals, slave_eth_dev);\n \n \tif (internals->slave_count < 1) {\n-\t\t/* if MAC is not user defined then use MAC of first slave add to bonded\n-\t\t * device */\n+\t\t/* if MAC is not user defined then use MAC of first slave add to\n+\t\t * bonded device */\n \t\tif (!internals->user_defined_mac)\n \t\t\tmac_address_set(bonded_eth_dev, slave_eth_dev->data->mac_addrs);\n \n \t\t/* Inherit eth dev link properties from first slave */\n-\t\tlink_properties_set(bonded_eth_dev, &(slave_eth_dev->data->dev_link));\n+\t\tlink_properties_set(bonded_eth_dev,\n+\t\t\t\t&(slave_eth_dev->data->dev_link));\n \n \t\t/* Make primary slave */\n \t\tinternals->primary_port = slave_port_id;\n@@ -322,10 +314,10 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)\n \t\tif (internals->link_props_set) {\n \t\t\tif (link_properties_valid(&(bonded_eth_dev->data->dev_link),\n \t\t\t\t\t\t\t\t\t  &(slave_eth_dev->data->dev_link))) {\n-\t\t\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\t\t\"%s: Slave port %d link speed/duplex not supported\\n\",\n-\t\t\t\t\t\t__func__, slave_port_id);\n-\t\t\t\tgoto err_add;\n+\t\t\t\tRTE_BOND_LOG(ERR,\n+\t\t\t\t\t\t\"Slave port %d link speed/duplex not supported\",\n+\t\t\t\t\t\tslave_port_id);\n+\t\t\t\treturn -1;\n \t\t\t}\n \t\t} else {\n \t\t\tlink_properties_set(bonded_eth_dev,\n@@ -340,9 +332,9 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)\n \n \tif (bonded_eth_dev->data->dev_started) {\n \t\tif (slave_configure(bonded_eth_dev, slave_eth_dev) != 0) {\n-\t\t\tRTE_LOG(ERR, PMD, \"rte_bond_slaves_configure: port=%d\\n\",\n+\t\t\tRTE_BOND_LOG(ERR, \"rte_bond_slaves_configure: port=%d\",\n \t\t\t\t\tslave_port_id);\n-\t\t\tgoto err_add;\n+\t\t\treturn -1;\n \t\t}\n \t}\n \n@@ -356,65 +348,79 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)\n \tif (bonded_eth_dev->data->dev_started) {\n \t\trte_eth_link_get_nowait(slave_port_id, &link_props);\n \n-\t\t if (link_props.link_status == 1) {\n+\t\t if (link_props.link_status == 1)\n \t\t\tinternals->active_slaves[internals->active_slave_count++] =\n \t\t\t\t\tslave_port_id;\n-\t\t}\n \t}\n-\n \treturn 0;\n \n-err_add:\n-\tRTE_LOG(ERR, PMD, \"Failed to add port %d as slave\\n\", slave_port_id);\n-\treturn -1;\n-\n }\n \n+\n int\n-rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)\n+rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)\n {\n+\tstruct rte_eth_dev *bonded_eth_dev;\n \tstruct bond_dev_private *internals;\n-\tstruct slave_conf *slave_conf;\n \n-\tint i;\n-\tint pos = -1;\n+\tint retval;\n \n \t/* Verify that port id's are valid bonded and slave ports */\n \tif (valid_bonded_port_id(bonded_port_id) != 0)\n-\t\tgoto err_del;\n+\t\treturn -1;\n+\n+\tbonded_eth_dev = &rte_eth_devices[bonded_port_id];\n+\tinternals = bonded_eth_dev->data->dev_private;\n+\n+\trte_spinlock_lock(&internals->lock);\n+\n+\tretval = __eth_bond_slave_add_lock_free(bonded_port_id, slave_port_id);\n+\n+\trte_spinlock_unlock(&internals->lock);\n+\n+\treturn retval;\n+}\n+\n+\n+static int\n+__eth_bond_slave_remove_lock_free(uint8_t bonded_port_id, uint8_t slave_port_id)\n+{\n+\tstruct bond_dev_private *internals;\n+\n+\tint i, slave_idx = -1;\n \n \tif (valid_slave_port_id(slave_port_id) != 0)\n-\t\tgoto err_del;\n+\t\treturn -1;\n \n \tinternals = rte_eth_devices[bonded_port_id].data->dev_private;\n \n \t/* first remove from active slave list */\n \tfor (i = 0; i < internals->active_slave_count; i++) {\n \t\tif (internals->active_slaves[i] == slave_port_id)\n-\t\t\tpos = i;\n+\t\t\tslave_idx = i;\n \n \t\t/* shift active slaves up active array list */\n-\t\tif (pos >= 0 && i < (internals->active_slave_count - 1))\n+\t\tif (slave_idx >= 0 && i < (internals->active_slave_count - 1))\n \t\t\tinternals->active_slaves[i] = internals->active_slaves[i+1];\n \t}\n \n-\tif (pos >= 0)\n+\tif (slave_idx >= 0)\n \t\tinternals->active_slave_count--;\n \n-\tpos = -1;\n-\t/* now remove from slave list */\n-\tfor (i = 0; i < internals->slave_count; i++) {\n-\t\tif (internals->slaves[i] == slave_port_id)\n-\t\t\tpos = i;\n+\tslave_idx = -1;\n+\t/* now find in slave list */\n+\tfor (i = 0; i < internals->slave_count; i++)\n+\t\tif (internals->slaves[i].port_id == slave_port_id) {\n+\t\t\tslave_idx = i;\n+\t\t\tbreak;\n+\t\t}\n \n-\t\t/* shift slaves up list */\n-\t\tif (pos >= 0 && i < internals->slave_count)\n-\t\t\tinternals->slaves[i] = internals->slaves[i+1];\n+\tif (slave_idx < 0) {\n+\t\tRTE_BOND_LOG(ERR, \"Couldn't find slave in port list, slave count %d\",\n+\t\t\t\tinternals->slave_count);\n+\t\treturn -1;\n \t}\n \n-\tif (pos < 0)\n-\t\tgoto err_del;\n-\n \t/* Un-register link status change callback with bonded device pointer as\n \t * argument*/\n \trte_eth_dev_callback_unregister(slave_port_id, RTE_ETH_EVENT_INTR_LSC,\n@@ -422,13 +428,10 @@ rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)\n \t\t\t&rte_eth_devices[bonded_port_id].data->port_id);\n \n \t/* Restore original MAC address of slave device */\n-\tslave_conf = slave_config_get(internals, slave_port_id);\n+\tmac_address_set(&rte_eth_devices[slave_port_id],\n+\t\t\t&(internals->slaves[slave_idx].persisted_mac_addr));\n \n-\tmac_address_set(&rte_eth_devices[slave_port_id], &(slave_conf->mac_addr));\n-\n-\tslave_config_clear(internals, &rte_eth_devices[slave_port_id]);\n-\n-\tinternals->slave_count--;\n+\tslave_remove(internals, &rte_eth_devices[slave_port_id]);\n \n \t/*  first slave in the active list will be the primary by default,\n \t *  otherwise use first device in list */\n@@ -436,7 +439,7 @@ rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)\n \t\tif (internals->active_slave_count > 0)\n \t\t\tinternals->current_primary_port = internals->active_slaves[0];\n \t\telse if (internals->slave_count > 0)\n-\t\t\tinternals->current_primary_port = internals->slaves[0];\n+\t\t\tinternals->current_primary_port = internals->slaves[0].port_id;\n \t\telse\n \t\t\tinternals->primary_port = 0;\n \t}\n@@ -454,12 +457,28 @@ rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)\n \t}\n \n \treturn 0;\n+}\n \n-err_del:\n-\tRTE_LOG(ERR, PMD,\n-\t\t\t\"Cannot remove slave device (not present in bonded device)\\n\");\n-\treturn -1;\n+int\n+rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)\n+{\n+\tstruct rte_eth_dev *bonded_eth_dev;\n+\tstruct bond_dev_private *internals;\n+\tint retval;\n+\n+\tif (valid_bonded_port_id(bonded_port_id) != 0)\n+\t\treturn -1;\n+\n+\tbonded_eth_dev = &rte_eth_devices[bonded_port_id];\n+\tinternals = bonded_eth_dev->data->dev_private;\n+\n+\trte_spinlock_lock(&internals->lock);\n+\n+\tretval = __eth_bond_slave_remove_lock_free(bonded_port_id, slave_port_id);\n+\n+\trte_spinlock_unlock(&internals->lock);\n \n+\treturn retval;\n }\n \n int\n@@ -524,6 +543,7 @@ int\n rte_eth_bond_slaves_get(uint8_t bonded_port_id, uint8_t slaves[], uint8_t len)\n {\n \tstruct bond_dev_private *internals;\n+\tint i;\n \n \tif (valid_bonded_port_id(bonded_port_id) != 0)\n \t\treturn -1;\n@@ -536,10 +556,10 @@ rte_eth_bond_slaves_get(uint8_t bonded_port_id, uint8_t slaves[], uint8_t len)\n \tif (internals->slave_count > len)\n \t\treturn -1;\n \n-\tmemcpy(slaves, internals->slaves, internals->slave_count);\n+\tfor (i = 0; i < internals->slave_count; i++)\n+\t\tslaves[i] = internals->slaves[i].port_id;\n \n \treturn internals->slave_count;\n-\n }\n \n int\n@@ -605,13 +625,13 @@ rte_eth_bond_mac_address_reset(uint8_t bonded_port_id)\n \tinternals->user_defined_mac = 0;\n \n \tif (internals->slave_count > 0) {\n-\t\tstruct slave_conf *conf;\n-\t\tconf = slave_config_get(internals, internals->primary_port);\n-\n \t\t/* Set MAC Address of Bonded Device */\n-\t\tif (mac_address_set(bonded_eth_dev, &conf->mac_addr) != 0)\n+\t\tif (mac_address_set(bonded_eth_dev,\n+\t\t\t\t&internals->slaves[internals->primary_port].persisted_mac_addr)\n+\t\t\t\t!= 0) {\n+\t\t\tRTE_BOND_LOG(ERR, \"Failed to set MAC address on bonded device\");\n \t\t\treturn -1;\n-\n+\t\t}\n \t\t/* Update all slave devices MAC addresses */\n \t\treturn mac_address_slaves_update(bonded_eth_dev);\n \t}\n@@ -654,3 +674,88 @@ rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id)\n \n \treturn internals->balance_xmit_policy;\n }\n+\n+\n+int\n+rte_eth_bond_link_monitoring_set(uint8_t bonded_port_id, uint32_t internal_ms)\n+{\n+\tstruct bond_dev_private *internals;\n+\n+\tif (valid_bonded_port_id(bonded_port_id) != 0)\n+\t\treturn -1;\n+\n+\tinternals = rte_eth_devices[bonded_port_id].data->dev_private;\n+\tinternals->link_status_polling_interval_ms = internal_ms;\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_eth_bond_link_monitoring_get(uint8_t bonded_port_id)\n+{\n+\tstruct bond_dev_private *internals;\n+\n+\tif (valid_bonded_port_id(bonded_port_id) != 0)\n+\t\treturn -1;\n+\n+\tinternals = rte_eth_devices[bonded_port_id].data->dev_private;\n+\n+\treturn internals->link_status_polling_interval_ms;\n+}\n+\n+int\n+rte_eth_bond_link_down_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms)\n+\n+{\n+\tstruct bond_dev_private *internals;\n+\n+\tif (valid_bonded_port_id(bonded_port_id) != 0)\n+\t\treturn -1;\n+\n+\tinternals = rte_eth_devices[bonded_port_id].data->dev_private;\n+\tinternals->link_down_delay_ms = delay_ms;\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_eth_bond_link_down_prop_delay_get(uint8_t bonded_port_id)\n+{\n+\tstruct bond_dev_private *internals;\n+\n+\tif (valid_bonded_port_id(bonded_port_id) != 0)\n+\t\treturn -1;\n+\n+\tinternals = rte_eth_devices[bonded_port_id].data->dev_private;\n+\n+\treturn internals->link_down_delay_ms;\n+}\n+\n+\n+int\n+rte_eth_bond_link_up_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms)\n+\n+{\n+\tstruct bond_dev_private *internals;\n+\n+\tif (valid_bonded_port_id(bonded_port_id) != 0)\n+\t\treturn -1;\n+\n+\tinternals = rte_eth_devices[bonded_port_id].data->dev_private;\n+\tinternals->link_up_delay_ms = delay_ms;\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_eth_bond_link_up_prop_delay_get(uint8_t bonded_port_id)\n+{\n+\tstruct bond_dev_private *internals;\n+\n+\tif (valid_bonded_port_id(bonded_port_id) != 0)\n+\t\treturn -1;\n+\n+\tinternals = rte_eth_devices[bonded_port_id].data->dev_private;\n+\n+\treturn internals->link_up_delay_ms;\n+}\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c\nindex 05a2b07..d8ce681 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_args.c\n+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c\n@@ -118,7 +118,7 @@ parse_port_id(const char *port_str)\n \t}\n \n \tif (port_id < 0 || port_id > RTE_MAX_ETHPORTS) {\n-\t\tRTE_LOG(ERR, PMD, \"Invalid slave port value (%s) specified.\\n\",\n+\t\tRTE_BOND_LOG(ERR, \"Slave port specified (%s) outside expected range\",\n \t\t\t\tport_str);\n \t\treturn -1;\n \t}\n@@ -138,9 +138,10 @@ bond_ethdev_parse_slave_port_kvarg(const char *key __rte_unused,\n \n \tif (strcmp(key, PMD_BOND_SLAVE_PORT_KVARG) == 0) {\n \t\tint port_id = parse_port_id(value);\n-\t\tif (port_id < 0)\n+\t\tif (port_id < 0) {\n+\t\t\tRTE_BOND_LOG(ERR, \"Invalid slave port value (%s) specified\", value);\n \t\t\treturn -1;\n-\t\telse\n+\t\t} else\n \t\t\tslave_ports->slaves[slave_ports->slave_count++] =\n \t\t\t\t\t(uint8_t)port_id;\n \t}\n@@ -174,6 +175,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,\n #endif\n \t\treturn 0;\n \tdefault:\n+\t\tRTE_BOND_LOG(ERR, \"Invalid slave mode value (%s) specified\", value);\n \t\treturn -1;\n \t}\n }\n@@ -252,3 +254,23 @@ bond_ethdev_parse_bond_mac_addr_kvarg(const char *key __rte_unused,\n \t/* Parse MAC */\n \treturn cmdline_parse_etheraddr(NULL, value, extra_args);\n }\n+\n+int\n+bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,\n+\t\tconst char *value, void *extra_args)\n+{\n+\tuint32_t time_ms;\n+\tchar *endptr;\n+\n+\tif (value == NULL || extra_args == NULL)\n+\t\treturn -1;\n+\n+\terrno = 0;\n+\ttime_ms = (uint32_t)strtol(value, &endptr, 10);\n+\tif (*endptr != 0 || errno != 0)\n+\t\treturn -1;\n+\n+\t*(uint32_t *)extra_args = time_ms;\n+\n+\treturn 0;\n+}\ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c\nindex 2a86402..b82a817 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c\n+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c\n@@ -40,6 +40,7 @@\n #include <rte_devargs.h>\n #include <rte_kvargs.h>\n #include <rte_dev.h>\n+#include <rte_alarm.h>\n \n #include \"rte_eth_bond.h\"\n #include \"rte_eth_bond_private.h\"\n@@ -457,16 +458,16 @@ mac_address_set(struct rte_eth_dev *eth_dev, struct ether_addr *new_mac_addr)\n \tmac_addr = eth_dev->data->mac_addrs;\n \n \tif (eth_dev == NULL) {\n-\t\tRTE_LOG(ERR, PMD, \"%s: NULL pointer eth_dev specified\\n\", __func__);\n+\t\tRTE_BOND_LOG(ERR,  \"NULL pointer eth_dev specified\");\n \t\treturn -1;\n \t}\n \n \tif (new_mac_addr == NULL) {\n-\t\tRTE_LOG(ERR, PMD, \"%s: NULL pointer MAC specified\\n\", __func__);\n+\t\tRTE_BOND_LOG(ERR, \"NULL pointer MAC specified\");\n \t\treturn -1;\n \t}\n \n-\t/* if new MAC is different to current MAC then update */\n+\t/* If new MAC is different to current MAC then update */\n \tif (memcmp(mac_addr, new_mac_addr, sizeof(*mac_addr)) != 0)\n \t\tmemcpy(mac_addr, new_mac_addr, sizeof(*mac_addr));\n \n@@ -490,11 +491,10 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)\n \tcase BONDING_MODE_BROADCAST:\n #endif\n \t\tfor (i = 0; i < internals->slave_count; i++) {\n-\t\t\tif (mac_address_set(&rte_eth_devices[internals->slaves[i]],\n+\t\t\tif (mac_address_set(&rte_eth_devices[internals->slaves[i].port_id],\n \t\t\t\t\tbonded_eth_dev->data->mac_addrs)) {\n-\t\t\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\t\t\"%s: Failed to update port Id %d MAC address\\n\",\n-\t\t\t\t\t\t__func__, internals->slaves[i]);\n+\t\t\t\tRTE_BOND_LOG(ERR, \"Failed to update port Id %d MAC address\",\n+\t\t\t\t\t\tinternals->slaves[i].port_id);\n \t\t\t\treturn -1;\n \t\t\t}\n \t\t}\n@@ -502,23 +502,20 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n \tdefault:\n \t\tfor (i = 0; i < internals->slave_count; i++) {\n-\t\t\tif (internals->slaves[i] == internals->current_primary_port) {\n+\t\t\tif (internals->slaves[i].port_id ==\n+\t\t\t\t\tinternals->current_primary_port) {\n \t\t\t\tif (mac_address_set(&rte_eth_devices[internals->primary_port],\n \t\t\t\t\t\tbonded_eth_dev->data->mac_addrs)) {\n-\t\t\t\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\t\t\t\"%s: Failed to update port Id %d MAC address\\n\",\n-\t\t\t\t\t\t\t__func__, internals->current_primary_port);\n+\t\t\t\t\tRTE_BOND_LOG(ERR, \"Failed to update port Id %d MAC address\",\n+\t\t\t\t\t\t\tinternals->current_primary_port);\n+\t\t\t\t\treturn -1;\n \t\t\t\t}\n \t\t\t} else {\n-\t\t\t\tstruct slave_conf *conf =\n-\t\t\t\t\t\tslave_config_get(internals, internals->slaves[i]);\n-\n-\t\t\t\tif (mac_address_set(&rte_eth_devices[internals->slaves[i]],\n-\t\t\t\t\t\t&conf->mac_addr)) {\n-\t\t\t\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\t\t\t\"%s: Failed to update port Id %d MAC address\\n\",\n-\t\t\t\t\t\t\t__func__, internals->slaves[i]);\n-\n+\t\t\t\tif (mac_address_set(\n+\t\t\t\t\t\t&rte_eth_devices[internals->slaves[i].port_id],\n+\t\t\t\t\t\t&internals->slaves[i].persisted_mac_addr)) {\n+\t\t\t\t\tRTE_BOND_LOG(ERR, \"Failed to update port Id %d MAC address\",\n+\t\t\t\t\t\t\tinternals->slaves[i].port_id);\n \t\t\t\t\treturn -1;\n \t\t\t\t}\n \t\t\t}\n@@ -570,34 +567,39 @@ slave_configure(struct rte_eth_dev *bonded_eth_dev,\n \tstruct bond_rx_queue *bd_rx_q;\n \tstruct bond_tx_queue *bd_tx_q;\n \n-\tint q_id;\n+\tint errval, q_id;\n \n \t/* Stop slave */\n \trte_eth_dev_stop(slave_eth_dev->data->port_id);\n \n-\t/* Enable interrupts on slave device */\n-\tslave_eth_dev->data->dev_conf.intr_conf.lsc = 1;\n+\t/* Enable interrupts on slave device if supported */\n+\tif (slave_eth_dev->driver->pci_drv.drv_flags & RTE_PCI_DRV_INTR_LSC)\n+\t\tslave_eth_dev->data->dev_conf.intr_conf.lsc = 1;\n \n-\tif (rte_eth_dev_configure(slave_eth_dev->data->port_id,\n+\t/* Configure device */\n+\terrval = rte_eth_dev_configure(slave_eth_dev->data->port_id,\n \t\t\tbonded_eth_dev->data->nb_rx_queues,\n \t\t\tbonded_eth_dev->data->nb_tx_queues,\n-\t\t\t&(slave_eth_dev->data->dev_conf)) != 0) {\n-\t\tRTE_LOG(ERR, PMD, \"Cannot configure slave device: port=%u\\n\",\n-\t\t\t\tslave_eth_dev->data->port_id);\n-\t\treturn -1;\n+\t\t\t&(slave_eth_dev->data->dev_conf));\n+\tif (errval != 0) {\n+\t\tRTE_BOND_LOG(ERR, \"Cannot configure slave device: port %u , err (%d)\",\n+\t\t\t\tslave_eth_dev->data->port_id, errval);\n+\t\treturn errval;\n \t}\n \n \t/* Setup Rx Queues */\n \tfor (q_id = 0; q_id < bonded_eth_dev->data->nb_rx_queues; q_id++) {\n \t\tbd_rx_q = (struct bond_rx_queue *)bonded_eth_dev->data->rx_queues[q_id];\n \n-\t\tif (rte_eth_rx_queue_setup(slave_eth_dev->data->port_id, q_id,\n+\t\terrval = rte_eth_rx_queue_setup(slave_eth_dev->data->port_id, q_id,\n \t\t\t\tbd_rx_q->nb_rx_desc,\n \t\t\t\trte_eth_dev_socket_id(slave_eth_dev->data->port_id),\n-\t\t\t\t&(bd_rx_q->rx_conf), bd_rx_q->mb_pool) != 0) {\n-\t\t\tRTE_LOG(ERR, PMD, \"rte_eth_rx_queue_setup: port=%d queue_id %d\\n\",\n-\t\t\t\t\tslave_eth_dev->data->port_id, q_id);\n-\t\t\treturn -1;\n+\t\t\t\t&(bd_rx_q->rx_conf), bd_rx_q->mb_pool);\n+\t\tif (errval != 0) {\n+\t\t\tRTE_BOND_LOG(ERR,\n+\t\t\t\t\t\"rte_eth_rx_queue_setup: port=%d queue_id %d, err (%d)\",\n+\t\t\t\t\tslave_eth_dev->data->port_id, q_id, errval);\n+\t\t\treturn errval;\n \t\t}\n \t}\n \n@@ -605,69 +607,77 @@ slave_configure(struct rte_eth_dev *bonded_eth_dev,\n \tfor (q_id = 0; q_id < bonded_eth_dev->data->nb_tx_queues; q_id++) {\n \t\tbd_tx_q = (struct bond_tx_queue *)bonded_eth_dev->data->tx_queues[q_id];\n \n-\t\tif (rte_eth_tx_queue_setup(slave_eth_dev->data->port_id, q_id,\n+\t\terrval = rte_eth_tx_queue_setup(slave_eth_dev->data->port_id, q_id,\n \t\t\t\tbd_tx_q->nb_tx_desc,\n \t\t\t\trte_eth_dev_socket_id(slave_eth_dev->data->port_id),\n-\t\t\t\t&bd_tx_q->tx_conf) != 0) {\n-\t\t\tRTE_LOG(ERR, PMD, \"rte_eth_tx_queue_setup: port=%d queue_id %d\\n\",\n-\t\t\t\t\tslave_eth_dev->data->port_id, q_id);\n-\t\t\treturn -1;\n+\t\t\t\t&bd_tx_q->tx_conf);\n+\t\tif (errval != 0) {\n+\t\t\tRTE_BOND_LOG(ERR,\n+\t\t\t\t\t\"rte_eth_tx_queue_setup: port=%d queue_id %d, err (%d)\",\n+\t\t\t\t\tslave_eth_dev->data->port_id, q_id, errval);\n+\t\t\treturn errval;\n \t\t}\n \t}\n \n \t/* Start device */\n-\tif (rte_eth_dev_start(slave_eth_dev->data->port_id) != 0) {\n-\t\tRTE_LOG(ERR, PMD, \"rte_eth_dev_start: port=%u\\n\",\n-\t\t\t\tslave_eth_dev->data->port_id);\n+\terrval = rte_eth_dev_start(slave_eth_dev->data->port_id);\n+\tif (errval != 0) {\n+\t\tRTE_BOND_LOG(ERR, \"rte_eth_dev_start: port=%u, err (%d)\",\n+\t\t\t\tslave_eth_dev->data->port_id, errval);\n \t\treturn -1;\n \t}\n \n \treturn 0;\n }\n \n-struct slave_conf *\n-slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id)\n-{\n-\tint i;\n-\n-\tfor (i = 0; i < internals->slave_count; i++) {\n-\t\tif (internals->presisted_slaves_conf[i].port_id == slave_port_id)\n-\t\t\treturn &internals->presisted_slaves_conf[i];\n-\t}\n-\treturn NULL;\n-}\n-\n void\n-slave_config_clear(struct bond_dev_private *internals,\n+slave_remove(struct bond_dev_private *internals,\n \t\tstruct rte_eth_dev *slave_eth_dev)\n {\n \tint i, found = 0;\n \n \tfor (i = 0; i < internals->slave_count; i++) {\n-\t\tif (internals->presisted_slaves_conf[i].port_id ==\n-\t\t\t\tslave_eth_dev->data->port_id) {\n+\t\tif (internals->slaves[i].port_id ==\tslave_eth_dev->data->port_id)\n \t\t\tfound = 1;\n-\t\t\tmemset(&internals->presisted_slaves_conf[i], 0,\n-\t\t\t\t\tsizeof(internals->presisted_slaves_conf[i]));\n-\t\t}\n-\t\tif (found && i < (internals->slave_count - 1)) {\n-\t\t\tmemcpy(&internals->presisted_slaves_conf[i],\n-\t\t\t\t\t&internals->presisted_slaves_conf[i+1],\n-\t\t\t\t\tsizeof(internals->presisted_slaves_conf[i]));\n-\t\t}\n+\n+\t\tif (found && i < (internals->slave_count - 1))\n+\t\t\tmemcpy(&internals->slaves[i], &internals->slaves[i+1],\n+\t\t\t\t\tsizeof(internals->slaves[i]));\n \t}\n+\n+\tinternals->slave_count--;\n }\n \n+static void\n+bond_ethdev_slave_link_status_change_monitor(void *cb_arg);\n+\n void\n-slave_config_store(struct bond_dev_private *internals,\n+slave_add(struct bond_dev_private *internals,\n \t\tstruct rte_eth_dev *slave_eth_dev)\n {\n-\tstruct slave_conf *presisted_slave_conf =\n-\t\t\t&internals->presisted_slaves_conf[internals->slave_count];\n+\tstruct bond_slave_details *slave_details =\n+\t\t\t&internals->slaves[internals->slave_count];\n+\n+\tslave_details->port_id = slave_eth_dev->data->port_id;\n+\tslave_details->last_link_status = 0;\n+\n+\t/* If slave device doesn't support interrupts then we need to enabled\n+\t * polling to monitor link status */\n+\tif (!(slave_eth_dev->pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_LSC)) {\n+\t\tslave_details->link_status_poll_enabled = 1;\n+\n+\t\tif (!internals->link_status_polling_enabled) {\n+\t\t\tinternals->link_status_polling_enabled = 1;\n \n-\tpresisted_slave_conf->port_id = slave_eth_dev->data->port_id;\n+\t\t\trte_eal_alarm_set(internals->link_status_polling_interval_ms * 1000,\n+\t\t\t\t\tbond_ethdev_slave_link_status_change_monitor,\n+\t\t\t\t\t(void *)&rte_eth_devices[internals->port_id]);\n+\t\t}\n+\t}\n \n-\tmemcpy(&(presisted_slave_conf->mac_addr), slave_eth_dev->data->mac_addrs,\n+\tslave_details->link_status_wait_to_complete = 0;\n+\n+\tmemcpy(&(slave_details->persisted_mac_addr), slave_eth_dev->data->mac_addrs,\n \t\t\tsizeof(struct ether_addr));\n }\n \n@@ -698,31 +708,33 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)\n \n \t/* slave eth dev will be started by bonded device */\n \tif (valid_bonded_ethdev(eth_dev)) {\n-\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\"%s: user tried to explicitly start a slave eth_dev (%d) of the bonded eth_dev\\n\",\n-\t\t\t\t__func__, eth_dev->data->port_id);\n+\t\tRTE_BOND_LOG(ERR, \"User tried to explicitly start a slave eth_dev (%d)\",\n+\t\t\t\teth_dev->data->port_id);\n \t\treturn -1;\n \t}\n \n-\teth_dev->data->dev_link.link_status = 1;\n+\teth_dev->data->dev_link.link_status = 0;\n \teth_dev->data->dev_started = 1;\n \n \tinternals = eth_dev->data->dev_private;\n \n \tif (internals->slave_count == 0) {\n-\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\"%s: Cannot start port since there are no slave devices\\n\",\n-\t\t\t\t__func__);\n+\t\tRTE_BOND_LOG(ERR, \"Cannot start port since there are no slave devices\");\n \t\treturn -1;\n \t}\n \n \tif (internals->user_defined_mac == 0) {\n-\t\tstruct slave_conf *conf = slave_config_get(internals,\n-\t\t\t\tinternals->primary_port);\n+\t\tstruct ether_addr *new_mac_addr = NULL;\n+\n+\t\tfor (i = 0; i < internals->slave_count; i++)\n+\t\t\tif (internals->slaves[i].port_id == internals->primary_port)\n+\t\t\t\tnew_mac_addr = &internals->slaves[i].persisted_mac_addr;\n+\n+\t\tif (new_mac_addr == NULL)\n+\t\t\treturn -1;\n \n-\t\tif (mac_address_set(eth_dev, &(conf->mac_addr)) != 0) {\n-\t\t\tRTE_LOG(ERR, PMD,\n-\t\t\t\t\t\"bonded port (%d) failed to update mac address\",\n+\t\tif (mac_address_set(eth_dev, new_mac_addr) != 0) {\n+\t\t\tRTE_BOND_LOG(ERR, \"bonded port (%d) failed to update MAC address\",\n \t\t\t\t\teth_dev->data->port_id);\n \t\t\treturn -1;\n \t\t}\n@@ -738,11 +750,11 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)\n \n \t/* Reconfigure each slave device if starting bonded device */\n \tfor (i = 0; i < internals->slave_count; i++) {\n-\t\tif (slave_configure(eth_dev, &(rte_eth_devices[internals->slaves[i]]))\n-\t\t\t\t!= 0) {\n-\t\t\tRTE_LOG(ERR, PMD, \"bonded port \"\n-\t\t\t\t\t\"(%d) failed to reconfigure slave device (%d)\\n)\",\n-\t\t\t\t\teth_dev->data->port_id, internals->slaves[i]);\n+\t\tif (slave_configure(eth_dev,\n+\t\t\t\t&(rte_eth_devices[internals->slaves[i].port_id])) != 0) {\n+\t\t\tRTE_BOND_LOG(ERR,\n+\t\t\t\t\t\"bonded port (%d) failed to reconfigure slave device (%d)\",\n+\t\t\t\t\teth_dev->data->port_id, internals->slaves[i].port_id);\n \t\t\treturn -1;\n \t\t}\n \t}\n@@ -759,6 +771,7 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)\n \tstruct bond_dev_private *internals = eth_dev->data->dev_private;\n \n \tinternals->active_slave_count = 0;\n+\tinternals->link_status_polling_enabled = 0;\n \n \teth_dev->data->dev_link.link_status = 0;\n \teth_dev->data->dev_started = 0;\n@@ -852,6 +865,65 @@ bond_ethdev_tx_queue_release(void *queue)\n \trte_free(queue);\n }\n \n+\n+static void\n+bond_ethdev_slave_link_status_change_monitor(void *cb_arg)\n+{\n+\tstruct rte_eth_dev *bonded_ethdev, *slave_ethdev;\n+\tstruct bond_dev_private *internals;\n+\n+\t/* Default value for polling slave found is true as we don't want to\n+\t * disable the polling thread if we cannot get the lock */\n+\tint i, polling_slave_found = 1;\n+\n+\tif (cb_arg == NULL)\n+\t\treturn;\n+\n+\tbonded_ethdev = (struct rte_eth_dev *)cb_arg;\n+\tinternals = (struct bond_dev_private *)bonded_ethdev->data->dev_private;\n+\n+\tif (!bonded_ethdev->data->dev_started ||\n+\t\t!internals->link_status_polling_enabled)\n+\t\treturn;\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+\t\tif (internals->slave_count > 0)\n+\t\t\tpolling_slave_found = 0;\n+\n+\t\tfor (i = 0; i < internals->slave_count; i++) {\n+\t\t\tif (!internals->slaves[i].link_status_poll_enabled)\n+\t\t\t\tcontinue;\n+\n+\t\t\tslave_ethdev = &rte_eth_devices[internals->slaves[i].port_id];\n+\t\t\tpolling_slave_found = 1;\n+\n+\t\t\t/* Update slave link status */\n+\t\t\t(*slave_ethdev->dev_ops->link_update)(slave_ethdev,\n+\t\t\t\t\tinternals->slaves[i].link_status_wait_to_complete);\n+\n+\t\t\t/* if link status has changed since last checked then call lsc\n+\t\t\t * event callback */\n+\t\t\tif (slave_ethdev->data->dev_link.link_status !=\n+\t\t\t\t\tinternals->slaves[i].last_link_status) {\n+\t\t\t\tinternals->slaves[i].last_link_status =\n+\t\t\t\t\t\tslave_ethdev->data->dev_link.link_status;\n+\n+\t\t\t\tbond_ethdev_lsc_event_callback(internals->slaves[i].port_id,\n+\t\t\t\t\t\tRTE_ETH_EVENT_INTR_LSC,\n+\t\t\t\t\t\t&bonded_ethdev->data->port_id);\n+\t\t\t}\n+\t\t}\n+\t\trte_spinlock_unlock(&internals->lock);\n+\t}\n+\n+\tif (polling_slave_found)\n+\t\t/* Set alarm to continue monitoring link status of slave ethdev's */\n+\t\trte_eal_alarm_set(internals->link_status_polling_interval_ms * 1000,\n+\t\t\t\tbond_ethdev_slave_link_status_change_monitor, cb_arg);\n+}\n+\n static int\n bond_ethdev_link_update(struct rte_eth_dev *bonded_eth_dev,\n \t\tint wait_to_complete)\n@@ -895,7 +967,7 @@ bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)\n \tmemset(stats, 0, sizeof(*stats));\n \n \tfor (i = 0; i < internals->slave_count; i++) {\n-\t\trte_eth_stats_get(internals->slaves[i], &slave_stats);\n+\t\trte_eth_stats_get(internals->slaves[i].port_id, &slave_stats);\n \n \t\tstats->ipackets += slave_stats.ipackets;\n \t\tstats->opackets += slave_stats.opackets;\n@@ -921,7 +993,7 @@ bond_ethdev_stats_reset(struct rte_eth_dev *dev)\n \tint i;\n \n \tfor (i = 0; i < internals->slave_count; i++)\n-\t\trte_eth_stats_reset(internals->slaves[i]);\n+\t\trte_eth_stats_reset(internals->slaves[i].port_id);\n }\n \n static void\n@@ -940,7 +1012,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)\n \tcase BONDING_MODE_BROADCAST:\n #endif\n \t\tfor (i = 0; i < internals->slave_count; i++)\n-\t\t\trte_eth_promiscuous_enable(internals->slaves[i]);\n+\t\t\trte_eth_promiscuous_enable(internals->slaves[i].port_id);\n \t\tbreak;\n \t/* Promiscuous mode is propagated only to primary slave */\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n@@ -966,7 +1038,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)\n \tcase BONDING_MODE_BROADCAST:\n #endif\n \t\tfor (i = 0; i < internals->slave_count; i++)\n-\t\t\trte_eth_promiscuous_disable(internals->slaves[i]);\n+\t\t\trte_eth_promiscuous_disable(internals->slaves[i].port_id);\n \t\tbreak;\n \t/* Promiscuous mode is propagated only to primary slave */\n \tcase BONDING_MODE_ACTIVE_BACKUP:\n@@ -975,6 +1047,16 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)\n \t}\n }\n \n+static void\n+bond_ethdev_delayed_lsc_propagation(void *arg)\n+{\n+\tif (arg == NULL)\n+\t\treturn;\n+\n+\t_rte_eth_dev_callback_process((struct rte_eth_dev *)arg,\n+\t\t\tRTE_ETH_EVENT_INTR_LSC);\n+}\n+\n void\n bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,\n \t\tvoid *param)\n@@ -1003,7 +1085,7 @@ bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,\n \n \t/* verify that port_id is a valid slave of bonded port */\n \tfor (i = 0; i < internals->slave_count; i++) {\n-\t\tif (internals->slaves[i] == port_id) {\n+\t\tif (internals->slaves[i].port_id == port_id) {\n \t\t\tvalid_slave = 1;\n \t\t\tbreak;\n \t\t}\n@@ -1072,8 +1154,32 @@ bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,\n \t\t}\n \t}\n \n-\tif (lsc_flag)\n-\t\t_rte_eth_dev_callback_process(bonded_eth_dev, RTE_ETH_EVENT_INTR_LSC);\n+\tif (lsc_flag) {\n+\t\t/* Cancel any possible outstanding interrupts if delays are enabled */\n+\t\tif (internals->link_up_delay_ms > 0 ||\n+\t\t\tinternals->link_down_delay_ms > 0)\n+\t\t\trte_eal_alarm_cancel(bond_ethdev_delayed_lsc_propagation,\n+\t\t\t\t\tbonded_eth_dev);\n+\n+\t\tif (bonded_eth_dev->data->dev_link.link_status) {\n+\t\t\tif (internals->link_up_delay_ms > 0)\n+\t\t\t\trte_eal_alarm_set(internals->link_up_delay_ms * 1000,\n+\t\t\t\t\t\tbond_ethdev_delayed_lsc_propagation,\n+\t\t\t\t\t\t(void *)bonded_eth_dev);\n+\t\t\telse\n+\t\t\t\t_rte_eth_dev_callback_process(bonded_eth_dev,\n+\t\t\t\t\t\tRTE_ETH_EVENT_INTR_LSC);\n+\n+\t\t} else {\n+\t\t\tif (internals->link_down_delay_ms > 0)\n+\t\t\t\trte_eal_alarm_set(internals->link_down_delay_ms * 1000,\n+\t\t\t\t\t\tbond_ethdev_delayed_lsc_propagation,\n+\t\t\t\t\t\t(void *)bonded_eth_dev);\n+\t\t\telse\n+\t\t\t\t_rte_eth_dev_callback_process(bonded_eth_dev,\n+\t\t\t\t\t\tRTE_ETH_EVENT_INTR_LSC);\n+\t\t}\n+\t}\n }\n \n struct eth_dev_ops default_dev_ops = {\n@@ -1223,8 +1329,8 @@ bond_ethdev_configure(struct rte_eth_dev *dev)\n \t\t}\n \t} else if (arg_count > 1) {\n \t\tRTE_LOG(ERR, EAL,\n-\t\t\t\t\"Transmit policy can be specified only once for bonded device %s\\n\",\n-\t\t\t\tname);\n+\t\t\t\t\"Transmit policy can be specified only once for bonded device\"\n+\t\t\t\t\" %s\\n\", name);\n \t\treturn -1;\n \t}\n \n@@ -1266,8 +1372,8 @@ bond_ethdev_configure(struct rte_eth_dev *dev)\n \t\t\t\t&bond_ethdev_parse_primary_slave_port_id_kvarg,\n \t\t\t\t&primary_slave_port_id) < 0) {\n \t\t\tRTE_LOG(INFO, EAL,\n-\t\t\t\t\t\"Invalid primary slave port id specified for bonded device %s\\n\",\n-\t\t\t\t\tname);\n+\t\t\t\t\t\"Invalid primary slave port id specified for bonded device\"\n+\t\t\t\t\t\" %s\\n\", name);\n \t\t\treturn -1;\n \t\t}\n \n@@ -1281,8 +1387,97 @@ bond_ethdev_configure(struct rte_eth_dev *dev)\n \t\t}\n \t} else if (arg_count > 1) {\n \t\tRTE_LOG(INFO, EAL,\n-\t\t\t\t\"Primary slave can be specified only once for bonded device %s\\n\",\n-\t\t\t\tname);\n+\t\t\t\t\"Primary slave can be specified only once for bonded device\"\n+\t\t\t\t\" %s\\n\", name);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Parse link status monitor polling interval */\n+\targ_count = rte_kvargs_count(kvlist, PMD_BOND_LSC_POLL_PERIOD_KVARG);\n+\tif (arg_count == 1) {\n+\t\tuint32_t lsc_poll_interval_ms;\n+\n+\t\tif (rte_kvargs_process(kvlist,\n+\t\t\t\tPMD_BOND_LSC_POLL_PERIOD_KVARG,\n+\t\t\t\t&bond_ethdev_parse_time_ms_kvarg,\n+\t\t\t\t&lsc_poll_interval_ms) < 0) {\n+\t\t\tRTE_LOG(INFO, EAL,\n+\t\t\t\t\t\"Invalid lsc polling interval value specified for bonded\"\n+\t\t\t\t\t\"device %s\\n\", name);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (rte_eth_bond_link_monitoring_set(port_id, lsc_poll_interval_ms)\n+\t\t\t\t!= 0) {\n+\t\t\tRTE_LOG(ERR, EAL,\n+\t\t\t\t\t\"Failed to set lsc monitor polling interval (%u ms) on\"\n+\t\t\t\t\t\" bonded device %s\\n\", lsc_poll_interval_ms, name);\n+\t\t\treturn -1;\n+\t\t}\n+\t} else if (arg_count > 1) {\n+\t\tRTE_LOG(INFO, EAL,\n+\t\t\t\t\"LSC polling interval can be specified only once for bonded\"\n+\t\t\t\t\"device %s\\n\", name);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Parse link up interrupt propagation delay */\n+\targ_count = rte_kvargs_count(kvlist, PMD_BOND_LINK_UP_PROP_DELAY_KVARG);\n+\tif (arg_count == 1) {\n+\t\tuint32_t link_up_delay_ms;\n+\n+\t\tif (rte_kvargs_process(kvlist,\n+\t\t\t\tPMD_BOND_LINK_UP_PROP_DELAY_KVARG,\n+\t\t\t\t&bond_ethdev_parse_time_ms_kvarg,\n+\t\t\t\t&link_up_delay_ms) < 0) {\n+\t\t\tRTE_LOG(INFO, EAL,\n+\t\t\t\t\t\"Invalid link up propagation delay value specified for \"\n+\t\t\t\t\t\"bonded device %s\\n\", name);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/* Set balance mode transmit policy*/\n+\t\tif (rte_eth_bond_link_up_prop_delay_set(port_id, link_up_delay_ms)\n+\t\t\t\t!= 0) {\n+\t\t\tRTE_LOG(ERR, EAL,\n+\t\t\t\t\t\"Failed to set link up propagation delay (%u ms) on bonded\"\n+\t\t\t\t\t\"device %s\\n\", link_up_delay_ms, name);\n+\t\t\treturn -1;\n+\t\t}\n+\t} else if (arg_count > 1) {\n+\t\tRTE_LOG(INFO, EAL,\n+\t\t\t\t\"Link up propagation delay can be specified only once for \"\n+\t\t\t\t\"bonded device %s\\n\", name);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Parse link down interrupt propagation delay */\n+\targ_count = rte_kvargs_count(kvlist, PMD_BOND_LINK_DOWN_PROP_DELAY_KVARG);\n+\tif (arg_count == 1) {\n+\t\tuint32_t link_down_delay_ms;\n+\n+\t\tif (rte_kvargs_process(kvlist,\n+\t\t\t\tPMD_BOND_LINK_DOWN_PROP_DELAY_KVARG,\n+\t\t\t\t&bond_ethdev_parse_time_ms_kvarg,\n+\t\t\t\t&link_down_delay_ms) < 0) {\n+\t\t\tRTE_LOG(INFO, EAL,\n+\t\t\t\t\t\"Invalid link down propagation delay value specified for\"\n+\t\t\t\t\t\"bonded device %s\\n\", name);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/* Set balance mode transmit policy*/\n+\t\tif (rte_eth_bond_link_down_prop_delay_set(port_id, link_down_delay_ms)\n+\t\t\t\t!= 0) {\n+\t\t\tRTE_LOG(ERR, EAL,\n+\t\t\t\t\t\"Failed to set link down propagation delay (%u ms) on\"\n+\t\t\t\t\t\" bonded device %s\\n\", link_down_delay_ms, name);\n+\t\t\treturn -1;\n+\t\t}\n+\t} else if (arg_count > 1) {\n+\t\tRTE_LOG(INFO, EAL,\n+\t\t\t\t\"Link down propagation delay can be specified only once for\"\n+\t\t\t\t\" bonded device %s\\n\", name);\n \t\treturn -1;\n \t}\n \ndiff --git a/lib/librte_pmd_bond/rte_eth_bond_private.h b/lib/librte_pmd_bond/rte_eth_bond_private.h\nindex 1db6e4d..78f4196 100644\n--- a/lib/librte_pmd_bond/rte_eth_bond_private.h\n+++ b/lib/librte_pmd_bond/rte_eth_bond_private.h\n@@ -39,20 +39,27 @@ extern \"C\" {\n #endif\n \n #include <rte_ethdev.h>\n+#include <rte_spinlock.h>\n \n #include \"rte_eth_bond.h\"\n \n-#define PMD_BOND_SLAVE_PORT_KVARG\t\t(\"slave\")\n-#define PMD_BOND_PRIMARY_SLAVE_KVARG\t(\"primary\")\n-#define PMD_BOND_MODE_KVARG\t\t\t\t(\"mode\")\n-#define PMD_BOND_XMIT_POLICY_KVARG\t\t(\"xmit_policy\")\n-#define PMD_BOND_SOCKET_ID_KVARG\t\t(\"socket_id\")\n-#define PMD_BOND_MAC_ADDR_KVARG\t\t\t(\"mac\")\n+#define PMD_BOND_SLAVE_PORT_KVARG\t\t\t(\"slave\")\n+#define PMD_BOND_PRIMARY_SLAVE_KVARG\t\t(\"primary\")\n+#define PMD_BOND_MODE_KVARG\t\t\t\t\t(\"mode\")\n+#define PMD_BOND_XMIT_POLICY_KVARG\t\t\t(\"xmit_policy\")\n+#define PMD_BOND_SOCKET_ID_KVARG\t\t\t(\"socket_id\")\n+#define PMD_BOND_MAC_ADDR_KVARG\t\t\t\t(\"mac\")\n+#define PMD_BOND_LSC_POLL_PERIOD_KVARG\t\t(\"lsc_poll_period_ms\")\n+#define PMD_BOND_LINK_UP_PROP_DELAY_KVARG\t(\"up_delay\")\n+#define PMD_BOND_LINK_DOWN_PROP_DELAY_KVARG\t(\"down_delay\")\n \n #define PMD_BOND_XMIT_POLICY_LAYER2_KVARG\t(\"l2\")\n #define PMD_BOND_XMIT_POLICY_LAYER23_KVARG\t(\"l23\")\n #define PMD_BOND_XMIT_POLICY_LAYER34_KVARG\t(\"l34\")\n \n+#define RTE_BOND_LOG(lvl, msg, ...) \t\t\\\n+\tRTE_LOG(lvl, PMD, \"%s(%d) - \" msg \"\\n\", __func__, __LINE__, ##__VA_ARGS__);\n+\n extern const char *pmd_bond_init_valid_arguments[];\n \n extern const char *driver_name;\n@@ -82,27 +89,36 @@ struct bond_tx_queue {\n \t/**< Copy of TX configuration structure for queue */\n };\n \n-/** Persisted Slave Configuration Structure */\n-struct slave_conf {\n-\tuint8_t port_id;\n-\t/**< Port Id of slave eth_dev */\n-\tstruct ether_addr mac_addr;\n-\t/**< Slave eth_dev original MAC address */\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 \tuint8_t slave_count;\t\t\t\t/**< Number of slaves */\n };\n \n+struct bond_slave_details {\n+\tuint8_t port_id;\n+\n+\tuint8_t link_status_poll_enabled;\n+\tuint8_t link_status_wait_to_complete;\n+\tuint8_t last_link_status;\n+\n+\t/**< Port Id of slave eth_dev */\n+\tstruct ether_addr persisted_mac_addr;\n+};\n+\n /** Link Bonding PMD device private configuration Structure */\n struct bond_dev_private {\n+\tuint8_t port_id;\t\t\t\t\t/**< Port Id of Bonded Port */\n \tuint8_t mode;\t\t\t\t\t\t/**< Link Bonding Mode */\n \n+\trte_spinlock_t lock;\n+\n \tuint8_t primary_port;\t\t\t\t/**< Primary Slave Port */\n \tuint8_t current_primary_port;\t\t/**< Primary Slave Port */\n \tuint8_t user_defined_primary_port;\n \t/**< Flag for whether primary port is user defined or not */\n+\n \tuint8_t balance_xmit_policy;\n \t/**< Transmit policy - l2 / l23 / l34 for operation in balance mode */\n \tuint8_t user_defined_mac;\n@@ -110,19 +126,23 @@ struct bond_dev_private {\n \tuint8_t promiscuous_en;\n \t/**< Enabled/disable promiscuous mode on slave devices */\n \tuint8_t link_props_set;\n-\t/**< Bonded eth_dev link properties set */\n+\t/**< flag to denote if the link properties are set */\n+\n+\tuint8_t link_status_polling_enabled;\n+\tuint32_t link_status_polling_interval_ms;\n+\n+\tuint32_t link_down_delay_ms;\n+\tuint32_t link_up_delay_ms;\n \n \tuint16_t nb_rx_queues;\t\t\t/**< Total number of rx queues */\n \tuint16_t nb_tx_queues;\t\t\t/**< Total number of tx queues*/\n \n-\tuint8_t slave_count;\t\t\t/**< Number of active slaves */\n-\tuint8_t active_slave_count;\t\t/**< Number of slaves */\n-\n+\tuint8_t active_slave_count;\t\t/**< Number of active slaves */\n \tuint8_t active_slaves[RTE_MAX_ETHPORTS];\t/**< Active slave list */\n-\tuint8_t slaves[RTE_MAX_ETHPORTS];\t\t\t/**< Slave list */\n \n-\t/** Persisted configuration of slaves */\n-\tstruct slave_conf presisted_slaves_conf[RTE_MAX_ETHPORTS];\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 \n \tstruct rte_kvargs *kvlist;\n };\n@@ -168,16 +188,13 @@ slave_configure(struct rte_eth_dev *bonded_eth_dev,\n \t\tstruct rte_eth_dev *slave_eth_dev);\n \n void\n-slave_config_clear(struct bond_dev_private *internals,\n+slave_remove(struct bond_dev_private *internals,\n \t\tstruct rte_eth_dev *slave_eth_dev);\n \n void\n-slave_config_store(struct bond_dev_private *internals,\n+slave_add(struct bond_dev_private *internals,\n \t\tstruct rte_eth_dev *slave_eth_dev);\n \n-struct slave_conf *\n-slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id);\n-\n void\n bond_ethdev_primary_set(struct bond_dev_private *internals,\n \t\tuint8_t slave_port_id);\n@@ -210,6 +227,10 @@ int\n bond_ethdev_parse_bond_mac_addr_kvarg(const char *key __rte_unused,\n \t\tconst char *value, void *extra_args);\n \n+int\n+bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,\n+\t\tconst char *value, void *extra_args);\n+\n #ifdef __cplusplus\n }\n #endif\n",
    "prefixes": [
        "dpdk-dev",
        "v6",
        "7/8"
    ]
}