Signed-off-by: Declan Doherty <declan.doherty at intel.com>
---
 app/test-pmd/cmdline.c                     |  63 +++++
 app/test/test.h                            |   7 +-
 app/test/test_link_bonding.c               | 258 ++++++++++++-------
 app/test/virtual_pmd.c                     |  17 +-
 app/test/virtual_pmd.h                     |  48 +++-
 lib/librte_pmd_bond/rte_eth_bond.h         |  80 ++++++
 lib/librte_pmd_bond/rte_eth_bond_api.c     | 315 +++++++++++++++--------
 lib/librte_pmd_bond/rte_eth_bond_args.c    |  30 ++-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c     | 393 +++++++++++++++++++++--------
 lib/librte_pmd_bond/rte_eth_bond_private.h |  71 ++++--
 10 files changed, 934 insertions(+), 348 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 15ca493..b14df61 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -439,6 +439,9 @@ static void cmd_help_long_parsed(void *parsed_result,

                        "set bonding xmit_balance_policy (port_id) 
(l2|l23|l34)\n"
                        "       Set the transmit balance policy for bonded 
device running in balance mode.\n\n"
+
+                       "set bonding mon_period (port_id) (value) \n"
+                       "       Set the bonding link status monitoring polling 
period in ms.\n\n"
 #endif

                        , list_pkt_forwarding_modes()
@@ -3705,6 +3708,65 @@ cmdline_parse_inst_t cmd_set_bond_mac_addr = {
                }
 };

+
+/* *** SET LINK STATUS MONITORING POLLING PERIOD ON BONDED DEVICE *** */
+struct cmd_set_bond_mon_period_result {
+       cmdline_fixed_string_t set;
+       cmdline_fixed_string_t bonding;
+       cmdline_fixed_string_t mon_period;
+       uint8_t port_num;
+       uint32_t period_ms;
+};
+
+static void cmd_set_bond_mon_period_parsed(void *parsed_result,
+               __attribute__((unused))  struct cmdline *cl,
+               __attribute__((unused)) void *data)
+{
+       struct cmd_set_bond_mon_period_result *res = parsed_result;
+       int ret;
+
+       if (res->port_num >= nb_ports) {
+               printf("Port id %d must be less than %d\n", res->port_num, 
nb_ports);
+               return;
+       }
+
+       ret = rte_eth_bond_link_monitoring_set(res->port_num, res->period_ms);
+
+       /* check the return value and print it if is < 0 */
+       if (ret < 0)
+               printf("set_bond_mac_addr error: (%s)\n", strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_set_bond_mon_period_set =
+               TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               set, "set");
+cmdline_parse_token_string_t cmd_set_bond_mon_period_bonding =
+               TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               bonding, "bonding");
+cmdline_parse_token_string_t cmd_set_bond_mon_period_mon_period =
+               TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               mon_period,     "mon_period");
+cmdline_parse_token_num_t cmd_set_bond_mon_period_portnum =
+               TOKEN_NUM_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               port_num, UINT8);
+cmdline_parse_token_num_t cmd_set_bond_mon_period_period_ms =
+               TOKEN_NUM_INITIALIZER(struct cmd_set_bond_mon_period_result,
+                               period_ms, UINT32);
+
+cmdline_parse_inst_t cmd_set_bond_mon_period = {
+               .f = cmd_set_bond_mon_period_parsed,
+               .data = (void *) 0,
+               .help_str = "set bonding mon_period (port_id) (period_ms): ",
+               .tokens = {
+                               (void *)&cmd_set_bond_mon_period_set,
+                               (void *)&cmd_set_bond_mon_period_bonding,
+                               (void *)&cmd_set_bond_mon_period_mon_period,
+                               (void *)&cmd_set_bond_mon_period_portnum,
+                               (void *)&cmd_set_bond_mon_period_period_ms,
+                               NULL
+               }
+};
+
 #endif /* RTE_LIBRTE_PMD_BOND */

 /* *** SET FORWARDING MODE *** */
@@ -7453,6 +7515,7 @@ cmdline_parse_ctx_t main_ctx[] = {
        (cmdline_parse_inst_t *) &cmd_create_bonded_device,
        (cmdline_parse_inst_t *) &cmd_set_bond_mac_addr,
        (cmdline_parse_inst_t *) &cmd_set_balance_xmit_policy,
+       (cmdline_parse_inst_t *) &cmd_set_bond_mon_period,
 #endif
        (cmdline_parse_inst_t *)&cmd_vlan_offload,
        (cmdline_parse_inst_t *)&cmd_vlan_tpid,
diff --git a/app/test/test.h b/app/test/test.h
index 98ab804..24b1640 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -62,14 +62,15 @@

 #define TEST_ASSERT_SUCCESS(val, msg, ...) do {                                
        \
                if (!(val == 0)) {                                              
                                \
-                       printf("TestCase %s() line %d failed: "                 
\
-                               msg "\n", __func__, __LINE__, ##__VA_ARGS__);   
\
+                       printf("TestCase %s() line %d failed (err %d): "        
\
+                               msg "\n", __func__, __LINE__, val,              
                \
+                               ##__VA_ARGS__);                                 
                                \
                        return -1;                                              
                                        \
                }                                                               
                                                \
 } while (0)

 #define TEST_ASSERT_FAIL(val, msg, ...) do {                                   
\
-               if (!(val != -1)) {                                             
                                \
+               if (!(val != 0)) {                                              
                                \
                        printf("TestCase %s() line %d failed: "                 
\
                                msg "\n", __func__, __LINE__, ##__VA_ARGS__);   
\
                        return -1;                                              
                                        \
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index 50355a3..c32b685 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -234,42 +234,34 @@ configure_ethdev(uint8_t port_id, uint8_t start, uint8_t 
en_isr)
        else
                default_pmd_conf.intr_conf.lsc = 0;

-       if (rte_eth_dev_configure(port_id, test_params->nb_rx_q,
-                       test_params->nb_tx_q, &default_pmd_conf) != 0) {
-               goto error;
-       }
+       TEST_ASSERT_SUCCESS(rte_eth_dev_configure(port_id, test_params->nb_rx_q,
+                       test_params->nb_tx_q, &default_pmd_conf),
+                       "rte_eth_dev_configure for port %d failed", port_id);

-       for (q_id = 0; q_id < test_params->nb_rx_q; q_id++) {
-               if (rte_eth_rx_queue_setup(port_id, q_id, RX_RING_SIZE,
+       for (q_id = 0; q_id < test_params->nb_rx_q; q_id++)
+               TEST_ASSERT_SUCCESS(rte_eth_rx_queue_setup(port_id, q_id, 
RX_RING_SIZE,
                                rte_eth_dev_socket_id(port_id), 
&rx_conf_default,
-                               test_params->mbuf_pool) < 0) {
-                       goto error;
-               }
-       }
+                               test_params->mbuf_pool) ,
+                               "rte_eth_rx_queue_setup for port %d failed", 
port_id);

-       for (q_id = 0; q_id < test_params->nb_tx_q; q_id++) {
-               if (rte_eth_tx_queue_setup(port_id, q_id, TX_RING_SIZE,
-                               rte_eth_dev_socket_id(port_id), 
&tx_conf_default) < 0) {
-                       printf("Failed to setup tx queue (%d).\n", q_id);
-                       goto error;
-               }
-       }
+       for (q_id = 0; q_id < test_params->nb_tx_q; q_id++)
+               TEST_ASSERT_SUCCESS(rte_eth_tx_queue_setup(port_id, q_id, 
TX_RING_SIZE,
+                               rte_eth_dev_socket_id(port_id), 
&tx_conf_default),
+                               "rte_eth_tx_queue_setup for port %d failed", 
port_id);

-       if (start) {
-               if (rte_eth_dev_start(port_id) < 0) {
-                       printf("Failed to start device (%d).\n", port_id);
-                       goto error;
-               }
-       }
-       return 0;
+       if (start)
+               TEST_ASSERT_SUCCESS(rte_eth_dev_start(port_id),
+                               "rte_eth_dev_start for port %d failed", 
port_id);

-error:
-       printf("Failed to configure ethdev %d\n", port_id);
-       return -1;
+       return 0;
 }

 static int slaves_initialized;

+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cvar = PTHREAD_COND_INITIALIZER;
+
+
 static int
 test_setup(void)
 {
@@ -310,7 +302,7 @@ test_setup(void)
                        snprintf(pmd_name, RTE_ETH_NAME_MAX_LEN, "eth_virt_%d", 
i);

                        test_params->slave_port_ids[i] = 
virtual_ethdev_create(pmd_name,
-                                       mac_addr, rte_socket_id());
+                                       mac_addr, rte_socket_id(), 1);
                        if (test_params->slave_port_ids[i] < 0) {
                                printf("Failed to create virtual virtual ethdev 
%s\n", pmd_name);
                                return -1;
@@ -414,34 +406,27 @@ test_create_bonded_device_with_invalid_params(void)
 static int
 test_add_slave_to_bonded_device(void)
 {
-       int retval, current_slave_count;
+       int current_slave_count;

        uint8_t slaves[RTE_MAX_ETHPORTS];

-       retval = rte_eth_bond_slave_add(test_params->bonded_port_id,
-                       
test_params->slave_port_ids[test_params->bonded_slave_count]);
-       if (retval != 0) {
-               printf("Failed to add slave (%d) to bonded port (%d).\n",
-                               test_params->bonded_port_id,
-                               
test_params->slave_port_ids[test_params->bonded_slave_count]);
-               return -1;
-       }
+       TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id,
+                       
test_params->slave_port_ids[test_params->bonded_slave_count]),
+                       "Failed to add slave (%d) to bonded port (%d).",
+                       
test_params->slave_port_ids[test_params->bonded_slave_count],
+                       test_params->bonded_port_id);

        current_slave_count = 
rte_eth_bond_slaves_get(test_params->bonded_port_id,
                        slaves, RTE_MAX_ETHPORTS);
-       if (current_slave_count != test_params->bonded_slave_count + 1) {
-               printf("Number of slaves (%d) is greater than expected (%d).\n",
-                               current_slave_count, 
test_params->bonded_slave_count + 1);
-               return -1;
-       }
+       TEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count 
+ 1,
+                       "Number of slaves (%d) is greater than expected (%d).",
+                       current_slave_count, test_params->bonded_slave_count + 
1);

        current_slave_count = rte_eth_bond_active_slaves_get(
                        test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS);
-       if (current_slave_count != 0) {
-               printf("Number of active slaves (%d) is not as expected 
(%d).\n",
-                               current_slave_count, 0);
-               return -1;
-       }
+       TEST_ASSERT_EQUAL(current_slave_count, 0,
+                                       "Number of active slaves (%d) is not as 
expected (%d).\n",
+                                       current_slave_count, 0);

        test_params->bonded_slave_count++;

@@ -476,27 +461,23 @@ test_add_slave_to_invalid_bonded_device(void)
 static int
 test_remove_slave_from_bonded_device(void)
 {
-       int retval, current_slave_count;
+       int current_slave_count;
        struct ether_addr read_mac_addr, *mac_addr;
        uint8_t slaves[RTE_MAX_ETHPORTS];

-       retval = rte_eth_bond_slave_remove(test_params->bonded_port_id,
-                       
test_params->slave_port_ids[test_params->bonded_slave_count-1]);
-       if (retval != 0) {
-               printf("\t Failed to remove slave %d from bonded port (%d).\n",
-                               
test_params->slave_port_ids[test_params->bonded_slave_count-1],
-                               test_params->bonded_port_id);
-               return -1;
-       }
+       
TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(test_params->bonded_port_id,
+                       
test_params->slave_port_ids[test_params->bonded_slave_count-1]),
+                       "Failed to remove slave %d from bonded port (%d).",
+                       
test_params->slave_port_ids[test_params->bonded_slave_count-1],
+                       test_params->bonded_port_id);


        current_slave_count = 
rte_eth_bond_slaves_get(test_params->bonded_port_id,
                        slaves, RTE_MAX_ETHPORTS);
-       if (current_slave_count != test_params->bonded_slave_count - 1) {
-               printf("Number of slaves (%d) is great than expected (%d).\n",
-                               current_slave_count, 0);
-               return -1;
-       }
+
+       TEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count 
- 1,
+                       "Number of slaves (%d) is great than expected (%d).\n",
+                       current_slave_count, test_params->bonded_slave_count - 
1);


        mac_addr = (struct ether_addr *)slave_mac;
@@ -506,10 +487,8 @@ test_remove_slave_from_bonded_device(void)
        rte_eth_macaddr_get(
                        
test_params->slave_port_ids[test_params->bonded_slave_count-1],
                        &read_mac_addr);
-       if (memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
-               printf("bonded port mac address not set to that of primary 
port\n");
-               return -1;
-       }
+       TEST_ASSERT_SUCCESS(memcmp(mac_addr, &read_mac_addr, 
sizeof(read_mac_addr)),
+                       "bonded port mac address not set to that of primary 
port\n");

        rte_eth_stats_reset(
                        
test_params->slave_port_ids[test_params->bonded_slave_count-1]);
@@ -888,21 +867,20 @@ test_set_primary_slave(void)
                return -1;
        }

+       /* Non bonded device */
+       retval = rte_eth_bond_primary_set(test_params->slave_port_ids[i],
+                       test_params->slave_port_ids[i]);
+       if (retval == 0) {
+               printf("Expected call to failed as invalid port specified.\n");
+               return -1;
+       }
+
        /* Set slave as primary
         * Verify slave it is now primary slave
         * Verify that MAC address of bonded device is that of primary slave
         * Verify that MAC address of all bonded slaves are that of primary 
slave
         */
        for (i = 0; i < 4; i++) {
-
-               /* Non bonded device */
-               retval = 
rte_eth_bond_primary_set(test_params->slave_port_ids[i],
-                               test_params->slave_port_ids[i]);
-               if (retval == 0) {
-                       printf("Expected call to failed as invalid port 
specified.\n");
-                       return -1;
-               }
-
                retval = rte_eth_bond_primary_set(test_params->bonded_port_id,
                                test_params->slave_port_ids[i]);
                if (retval != 0) {
@@ -926,6 +904,7 @@ test_set_primary_slave(void)

                /* stop/start bonded eth dev to apply new MAC */
                rte_eth_dev_stop(test_params->bonded_port_id);
+
                if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
                        return -1;

@@ -1090,19 +1069,18 @@ static int
 initialize_bonded_device_with_slaves(uint8_t bonding_mode, uint8_t bond_en_isr,
                uint8_t number_of_slaves, uint8_t enable_slave)
 {
-       /* configure bonded device */
+       /* Configure bonded device */
        TEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 0,
                        bond_en_isr), "Failed to configure bonding port (%d) in 
mode %d "
                        "with (%d) slaves.", test_params->bonded_port_id, 
bonding_mode,
                        number_of_slaves);

-       while (number_of_slaves > test_params->bonded_slave_count) {
-               /* Add slaves to bonded device */
+       /* Add slaves to bonded device */
+       while (number_of_slaves > test_params->bonded_slave_count)
                TEST_ASSERT_SUCCESS(test_add_slave_to_bonded_device(),
                                "Failed to add slave (%d to  bonding port 
(%d).",
                                test_params->bonded_slave_count - 1,
                                test_params->bonded_port_id);
-       }

        /* Set link bonding mode  */
        TEST_ASSERT_SUCCESS(rte_eth_bond_mode_set(test_params->bonded_port_id,
@@ -1125,9 +1103,9 @@ test_adding_slave_after_bonded_device_started(void)
 {
        int i;

-       if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 0, 
4, 0)
-                       != 0)
-               return -1;
+       TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
+                       BONDING_MODE_ROUND_ROBIN, 0, 4, 0),
+                       "Failed to add slaves to bonded device");

        /* Enabled slave devices */
        for (i = 0; i < test_params->bonded_slave_count + 1; i++) {
@@ -1135,12 +1113,9 @@ test_adding_slave_after_bonded_device_started(void)
                                test_params->slave_port_ids[i], 1);
        }

-       if (rte_eth_bond_slave_add(test_params->bonded_port_id,
-                       
test_params->slave_port_ids[test_params->bonded_slave_count]) !=
-                                       0) {
-               printf("\t Failed to add slave to bonded port.\n");
-               return -1;
-       }
+       TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id,
+                       
test_params->slave_port_ids[test_params->bonded_slave_count]),
+                       "Failed to add slave to bonded port.\n");

        rte_eth_stats_reset(
                        
test_params->slave_port_ids[test_params->bonded_slave_count]);
@@ -1155,8 +1130,6 @@ test_adding_slave_after_bonded_device_started(void)

 int test_lsc_interupt_count;

-static pthread_mutex_t mutex;
-static pthread_cond_t cvar;

 static void
 test_bonding_lsc_event_callback(uint8_t port_id __rte_unused,
@@ -1180,7 +1153,7 @@ lsc_timeout(int wait_us)
        gettimeofday(&tp, NULL);

        /* Convert from timeval to timespec */
-       ts.tv_sec  = tp.tv_sec;
+       ts.tv_sec = tp.tv_sec;
        ts.tv_nsec = tp.tv_usec * 1000;
        ts.tv_nsec += wait_us * 1000;

@@ -1190,6 +1163,9 @@ lsc_timeout(int wait_us)

        pthread_mutex_unlock(&mutex);

+       if (retval == 0 && test_lsc_interupt_count < 1)
+               return -1;
+
        return retval;
 }

@@ -1199,9 +1175,6 @@ test_status_interrupt(void)
        int slave_count;
        uint8_t slaves[RTE_MAX_ETHPORTS];

-       pthread_mutex_init(&mutex, NULL);
-       pthread_cond_init(&cvar, NULL);
-
        /* initialized bonding device with T slaves */
        if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 1,
                        TEST_STATUS_INTERRUPT_SLAVE_COUNT, 1) != 0)
@@ -1281,9 +1254,6 @@ test_status_interrupt(void)
                                RTE_ETH_EVENT_INTR_LSC, 
test_bonding_lsc_event_callback,
                                &test_params->bonded_port_id);

-       pthread_mutex_destroy(&mutex);
-       pthread_cond_destroy(&cvar);
-
        /* Clean up and remove slaves from bonded device */
        return remove_slaves_and_stop_bonded_device();
 }
@@ -2025,6 +1995,101 @@ 
test_roundrobin_verify_slave_link_status_change_behaviour(void)
        return remove_slaves_and_stop_bonded_device();
 }

+#define TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT (2)
+
+uint8_t polling_slave_mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00 };
+
+#include "unistd.h"
+
+int polling_test_slaves[TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT] = { -1, -1 } ;
+
+static int
+test_roundrobin_verfiy_polling_slave_link_status_change(void)
+{
+       struct ether_addr *mac_addr = (struct ether_addr *)polling_slave_mac;
+       char slave_name[RTE_ETH_NAME_MAX_LEN];
+
+       int i;
+
+       for (i = 0; i < TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT; i++) {
+               /* Generate slave name / MAC address */
+               snprintf(slave_name, RTE_ETH_NAME_MAX_LEN, "eth_virt_poll_%d", 
i);
+               mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i;
+
+               /* Create slave devices with no ISR Support */
+               if (polling_test_slaves[i] == -1) {
+                       polling_test_slaves[i] = 
virtual_ethdev_create(slave_name, mac_addr,
+                                       rte_socket_id(), 0);
+                       TEST_ASSERT(polling_test_slaves[i] >= 0,
+                                       "Failed to create virtual virtual 
ethdev %s\n", slave_name);
+
+                       /* Configure slave */
+                       
TEST_ASSERT_SUCCESS(configure_ethdev(polling_test_slaves[i], 0, 0),
+                                       "Failed to configure virtual ethdev 
%s(%d)", slave_name,
+                                       polling_test_slaves[i]);
+               }
+
+               /* Add slave to bonded device */
+               
TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id,
+                               polling_test_slaves[i]),
+                               "Failed to add slave %s(%d) to bonded device 
%d",
+                               slave_name, polling_test_slaves[i], 
test_params->bonded_port_id);
+       }
+
+       /* Initialize bonded device */
+       TEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 1, 1),
+                       "Failed to configure bonded device %d",
+                       test_params->bonded_port_id);
+
+
+       /* Register link status change interrupt callback */
+       rte_eth_dev_callback_register(test_params->bonded_port_id,
+                       RTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback,
+                       &test_params->bonded_port_id);
+
+       /* link status change callback for first slave link up */
+       test_lsc_interupt_count = 0;
+
+       virtual_ethdev_set_link_status(polling_test_slaves[0], 1);
+
+       TEST_ASSERT_SUCCESS(lsc_timeout(15000), "timed out waiting for 
interrupt");
+
+
+       /* no link status change callback for second slave link up */
+       test_lsc_interupt_count = 0;
+
+       virtual_ethdev_set_link_status(polling_test_slaves[1], 1);
+
+       TEST_ASSERT_FAIL(lsc_timeout(15000), "unexpectedly succeeded");
+
+       /* link status change callback for both slave links down */
+       test_lsc_interupt_count = 0;
+
+       virtual_ethdev_set_link_status(polling_test_slaves[0], 0);
+       virtual_ethdev_set_link_status(polling_test_slaves[1], 0);
+
+       TEST_ASSERT_SUCCESS(lsc_timeout(20000), "timed out waiting for 
interrupt");
+
+       /* Un-Register link status change interrupt callback */
+       rte_eth_dev_callback_unregister(test_params->bonded_port_id,
+                       RTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback,
+                       &test_params->bonded_port_id);
+
+
+       /* Clean up and remove slaves from bonded device */
+       for (i = 0; i < TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT; i++) {
+
+               TEST_ASSERT_SUCCESS(
+                               
rte_eth_bond_slave_remove(test_params->bonded_port_id,
+                                               polling_test_slaves[i]),
+                               "Failed to remove slave %d from bonded port 
(%d)",
+                               polling_test_slaves[i], 
test_params->bonded_port_id);
+       }
+
+       return remove_slaves_and_stop_bonded_device();
+}
+
+
 /** Active Backup Mode Tests */

 static int
@@ -4311,6 +4376,7 @@ static struct unit_test_suite link_bonding_test_suite  = {
                TEST_CASE(test_roundrobin_verify_promiscuous_enable_disable),
                TEST_CASE(test_roundrobin_verify_mac_assignment),
                
TEST_CASE(test_roundrobin_verify_slave_link_status_change_behaviour),
+               
TEST_CASE(test_roundrobin_verfiy_polling_slave_link_status_change),
                TEST_CASE(test_activebackup_tx_burst),
                TEST_CASE(test_activebackup_rx_burst),
                TEST_CASE(test_activebackup_verify_promiscuous_enable_disable),
diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
index f9bd841..fffaa35 100644
--- a/app/test/virtual_pmd.c
+++ b/app/test/virtual_pmd.c
@@ -458,6 +458,14 @@ virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t 
port_id,
 }

 void
+virtual_ethdev_set_link_status(uint8_t port_id, uint8_t link_status)
+{
+       struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+       vrtl_eth_dev->data->dev_link.link_status = link_status;
+}
+
+void
 virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
                uint8_t link_status)
 {
@@ -505,7 +513,7 @@ get_number_of_sockets(void)

 int
 virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
-               uint8_t socket_id)
+               uint8_t socket_id, uint8_t isr_support)
 {
        struct rte_pci_device *pci_dev = NULL;
        struct rte_eth_dev *eth_dev = NULL;
@@ -555,7 +563,12 @@ virtual_ethdev_create(const char *name, struct ether_addr 
*mac_addr,
        pci_dev->numa_node = socket_id;
        pci_drv->name = virtual_ethdev_driver_name;
        pci_drv->id_table = id_table;
-       pci_drv->drv_flags = RTE_PCI_DRV_INTR_LSC;
+
+       if (isr_support)
+               pci_drv->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+       else
+               pci_drv->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
+

        eth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);
        eth_dev->driver = eth_drv;
diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h
index 3b5c911..2462853 100644
--- a/app/test/virtual_pmd.h
+++ b/app/test/virtual_pmd.h
@@ -40,38 +40,58 @@ extern "C" {

 #include <rte_ether.h>

-int virtual_ethdev_init(void);
+int
+virtual_ethdev_init(void);

-int virtual_ethdev_create(const char *name, struct ether_addr *mac_addr, 
uint8_t socket_id);
+int
+virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
+               uint8_t socket_id, uint8_t isr_support);

-void virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id, uint8_t 
link_status);
+void
+virtual_ethdev_set_link_status(uint8_t port_id, uint8_t link_status);

-void virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id, struct rte_mbuf 
**pkts_burst, int burst_length);
+void
+virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
+               uint8_t link_status);

+void
+virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id,
+               struct rte_mbuf **pkts_burst, int burst_length);

-/** Control methods for the dev_ops functions pointer to control the behavior 
of the Virtual PMD */

-void virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success);
+/** Control methods for the dev_ops functions pointer to control the behavior
+ *  of the Virtual PMD */

-void virtual_ethdev_stop_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success);

-void virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_stop_fn_set_success(uint8_t port_id, uint8_t success);

-void virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t 
success);
+void
+virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success);

-void virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t 
success);
+void
+virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);

-void virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t 
success);
+void
+virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success);

-void virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success);

-void virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success);
+void
+virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success);
+
+void
+virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success);

 /* if a value greater than zero is set for packet_fail_count then virtual
  * device tx burst function will fail that many packet from burst or all
  * packets if packet_fail_count is greater than the number of packets in the
  * burst */
-void virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id,
+void
+virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id,
                uint8_t packet_fail_count);

 #ifdef __cplusplus
diff --git a/lib/librte_pmd_bond/rte_eth_bond.h 
b/lib/librte_pmd_bond/rte_eth_bond.h
index bd59780..6811c7b 100644
--- a/lib/librte_pmd_bond/rte_eth_bond.h
+++ b/lib/librte_pmd_bond/rte_eth_bond.h
@@ -248,6 +248,86 @@ rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, 
uint8_t policy);
 int
 rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id);

+/**
+ * Set the link monitoring frequency (in ms) for monitoring the link status of
+ * slave devices
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param internal_ms          Monitoring interval in milliseconds
+ *
+ * @return
+ *     0 on success, negative value otherwise.
+ */
+
+int
+rte_eth_bond_link_monitoring_set(uint8_t bonded_port_id, uint32_t internal_ms);
+
+/**
+ * Get the current link monitoring frequency (in ms) for monitoring of the link
+ * status of slave devices
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ *
+ * @return
+ *     Monitoring interval on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_monitoring_get(uint8_t bonded_port_id);
+
+
+/**
+ * Set the period in milliseconds for delaying the disabling of a bonded link
+ * when the link down status has been detected
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param delay_ms                     Delay period in milliseconds.
+ *
+ * @return
+ *  0 on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_down_prop_delay_set(uint8_t bonded_port_id, uint32_t 
delay_ms);
+
+/**
+ * Get the period in milliseconds set for delaying the disabling of a bonded
+ * link when the link down status has been detected
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param delay_ms                     Delay period in milliseconds.
+ *
+ * @return
+ *  Delay period on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_down_prop_delay_get(uint8_t bonded_port_id);
+
+/**
+ * Set the period in milliseconds for delaying the enabling of a bonded link
+ * when the link up status has been detected
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param delay_ms                     Delay period in milliseconds.
+ *
+ * @return
+ *  0 on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_up_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms);
+
+/**
+ * Get the period in milliseconds set for delaying the enabling of a bonded
+ * link when the link up status has been detected
+ *
+ * @param bonded_port_id       Port ID of bonded device.
+ * @param delay_ms                     Delay period in milliseconds.
+ *
+ * @return
+ *  Delay period on success, negative value otherwise.
+ */
+int
+rte_eth_bond_link_up_prop_delay_get(uint8_t bonded_port_id);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c 
b/lib/librte_pmd_bond/rte_eth_bond_api.c
index dd33119..f146bda 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_api.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c
@@ -39,6 +39,8 @@
 #include "rte_eth_bond.h"
 #include "rte_eth_bond_private.h"

+#define DEFAULT_POLLING_INTERVAL_10_MS (10)
+
 int
 valid_bonded_ethdev(struct rte_eth_dev *eth_dev)
 {
@@ -63,9 +65,8 @@ valid_port_id(uint8_t port_id)
        /* Verify that port id is valid */
        int ethdev_count = rte_eth_dev_count();
        if (port_id >= ethdev_count) {
-               RTE_LOG(ERR, PMD,
-                               "%s: port Id %d is greater than 
rte_eth_dev_count %d\n",
-                               __func__, port_id, ethdev_count);
+               RTE_BOND_LOG(ERR, "Port Id %d is greater than rte_eth_dev_count 
%d",
+                               port_id, ethdev_count);
                return -1;
        }

@@ -81,9 +82,8 @@ valid_bonded_port_id(uint8_t port_id)

        /* Verify that bonded_port_id refers to a bonded port */
        if (valid_bonded_ethdev(&rte_eth_devices[port_id])) {
-               RTE_LOG(ERR, PMD,
-                               "%s: Specified port Id %d is not a bonded 
eth_dev device\n",
-                               __func__, port_id);
+               RTE_BOND_LOG(ERR, "Specified port Id %d is not a bonded eth_dev 
device",
+                               port_id);
                return -1;
        }

@@ -136,37 +136,36 @@ rte_eth_bond_create(const char *name, uint8_t mode, 
uint8_t socket_id)
         */

        if (name == NULL) {
-               RTE_LOG(ERR, PMD, "Invalid name specified\n");
+               RTE_BOND_LOG(ERR, "Invalid name specified");
                goto err;
        }

        if (socket_id >= number_of_sockets()) {
-               RTE_LOG(ERR, PMD,
-                               "%s: invalid socket id specified to create 
bonded device on.\n",
-                               __func__);
+               RTE_BOND_LOG(ERR,
+                               "Invalid socket id specified to create bonded 
device on.");
                goto err;
        }

        pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, socket_id);
        if (pci_dev == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc pci dev on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc pci dev on socket");
                goto err;
        }

        eth_drv = rte_zmalloc_socket(name, sizeof(*eth_drv), 0, socket_id);
        if (eth_drv == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc eth_drv on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc eth_drv on socket");
                goto err;
        }

        pci_drv = rte_zmalloc_socket(name, sizeof(*pci_drv), 0, socket_id);
        if (pci_drv == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc pci_drv on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc pci_drv on socket");
                goto err;
        }
        pci_id_table = rte_zmalloc_socket(name, sizeof(*pci_id_table), 0, 
socket_id);
        if (pci_drv == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc pci_id_table on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc pci_id_table on socket");
                goto err;
        }

@@ -181,14 +180,14 @@ rte_eth_bond_create(const char *name, uint8_t mode, 
uint8_t socket_id)

        internals = rte_zmalloc_socket(name, sizeof(*internals), 0, socket_id);
        if (internals == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to malloc internals on socket\n");
+               RTE_BOND_LOG(ERR, "Unable to malloc internals on socket");
                goto err;
        }

        /* reserve an ethdev entry */
        eth_dev = rte_eth_dev_allocate(name);
        if (eth_dev == NULL) {
-               RTE_LOG(ERR, PMD, "Unable to allocate rte_eth_dev\n");
+               RTE_BOND_LOG(ERR, "Unable to allocate rte_eth_dev");
                goto err;
        }

@@ -218,25 +217,31 @@ rte_eth_bond_create(const char *name, uint8_t mode, 
uint8_t socket_id)
        eth_dev->pci_dev = pci_dev;

        if (bond_ethdev_mode_set(eth_dev, mode)) {
-               RTE_LOG(ERR, PMD,
-                               "%s: failed to set bonded device %d mode too 
%d\n",
-                               __func__, eth_dev->data->port_id, mode);
+               RTE_BOND_LOG(ERR, "Failed to set bonded device %d mode too %d",
+                                eth_dev->data->port_id, mode);
                goto err;
        }

+       rte_spinlock_init(&internals->lock);
+
+       internals->port_id = eth_dev->data->port_id;
        internals->current_primary_port = 0;
        internals->balance_xmit_policy = BALANCE_XMIT_POLICY_LAYER2;
        internals->user_defined_mac = 0;
        internals->link_props_set = 0;
+
+       internals->link_status_polling_enabled = 0;
+
+       internals->link_status_polling_interval_ms = 
DEFAULT_POLLING_INTERVAL_10_MS;
+       internals->link_down_delay_ms = 0;
+       internals->link_up_delay_ms = 0;
+
        internals->slave_count = 0;
        internals->active_slave_count = 0;

        memset(internals->active_slaves, 0, sizeof(internals->active_slaves));
        memset(internals->slaves, 0, sizeof(internals->slaves));

-       memset(internals->presisted_slaves_conf, 0,
-                       sizeof(internals->presisted_slaves_conf));
-
        return eth_dev->data->port_id;

 err:
@@ -253,8 +258,8 @@ err:
        return -1;
 }

-int
-rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)
+static int
+__eth_bond_slave_add_lock_free(uint8_t bonded_port_id, uint8_t slave_port_id)
 {
        struct rte_eth_dev *bonded_eth_dev, *slave_eth_dev;
        struct bond_dev_private *internals;
@@ -263,56 +268,43 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t 
slave_port_id)

        int i, j;

-       /* Verify that port id's are valid bonded and slave ports */
-       if (valid_bonded_port_id(bonded_port_id) != 0)
-               goto err_add;
-
        if (valid_slave_port_id(slave_port_id) != 0)
-               goto err_add;
+               return -1;
+
+       bonded_eth_dev = &rte_eth_devices[bonded_port_id];
+       internals = bonded_eth_dev->data->dev_private;

-       /*
-        * Verify that new slave device is not already a slave of another bonded
-        * device */
+       /* Verify that new slave device is not already a slave of another
+        * bonded device */
        for (i = rte_eth_dev_count()-1; i >= 0; i--) {
                if (valid_bonded_ethdev(&rte_eth_devices[i]) == 0) {
                        temp_internals = rte_eth_devices[i].data->dev_private;
+
                        for (j = 0; j < temp_internals->slave_count; j++) {
                                /* Device already a slave of a bonded device */
-                               if (temp_internals->slaves[j] == slave_port_id)
-                                       goto err_add;
+                               if (temp_internals->slaves[j].port_id == 
slave_port_id) {
+                                       RTE_BOND_LOG(ERR, "Slave port %d is 
already a slave",
+                                                       slave_port_id);
+                                       return -1;
+                               }
                        }
                }
        }

-       bonded_eth_dev = &rte_eth_devices[bonded_port_id];
-       internals = bonded_eth_dev->data->dev_private;
-
        slave_eth_dev = &rte_eth_devices[slave_port_id];

-       if (internals->slave_count > 0) {
-               /* Check that new slave device is the same type as the other 
slaves
-                * and not repetitive */
-               for (i = 0; i < internals->slave_count; i++) {
-                       if (slave_eth_dev->pci_dev->driver->id_table->device_id 
!=
-                                       
rte_eth_devices[internals->slaves[i]].pci_dev->driver->id_table->device_id ||
-                               internals->slaves[i] == slave_port_id)
-                               goto err_add;
-               }
-       }
-
        /* Add slave details to bonded device */
-       internals->slaves[internals->slave_count] = slave_port_id;
-
-       slave_config_store(internals, slave_eth_dev);
+       slave_add(internals, slave_eth_dev);

        if (internals->slave_count < 1) {
-               /* if MAC is not user defined then use MAC of first slave add 
to bonded
-                * device */
+               /* if MAC is not user defined then use MAC of first slave add to
+                * bonded device */
                if (!internals->user_defined_mac)
                        mac_address_set(bonded_eth_dev, 
slave_eth_dev->data->mac_addrs);

                /* Inherit eth dev link properties from first slave */
-               link_properties_set(bonded_eth_dev, 
&(slave_eth_dev->data->dev_link));
+               link_properties_set(bonded_eth_dev,
+                               &(slave_eth_dev->data->dev_link));

                /* Make primary slave */
                internals->primary_port = slave_port_id;
@@ -322,10 +314,10 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t 
slave_port_id)
                if (internals->link_props_set) {
                        if 
(link_properties_valid(&(bonded_eth_dev->data->dev_link),
                                                                          
&(slave_eth_dev->data->dev_link))) {
-                               RTE_LOG(ERR, PMD,
-                                               "%s: Slave port %d link 
speed/duplex not supported\n",
-                                               __func__, slave_port_id);
-                               goto err_add;
+                               RTE_BOND_LOG(ERR,
+                                               "Slave port %d link 
speed/duplex not supported",
+                                               slave_port_id);
+                               return -1;
                        }
                } else {
                        link_properties_set(bonded_eth_dev,
@@ -340,9 +332,9 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t 
slave_port_id)

        if (bonded_eth_dev->data->dev_started) {
                if (slave_configure(bonded_eth_dev, slave_eth_dev) != 0) {
-                       RTE_LOG(ERR, PMD, "rte_bond_slaves_configure: 
port=%d\n",
+                       RTE_BOND_LOG(ERR, "rte_bond_slaves_configure: port=%d",
                                        slave_port_id);
-                       goto err_add;
+                       return -1;
                }
        }

@@ -356,65 +348,79 @@ rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t 
slave_port_id)
        if (bonded_eth_dev->data->dev_started) {
                rte_eth_link_get_nowait(slave_port_id, &link_props);

-                if (link_props.link_status == 1) {
+                if (link_props.link_status == 1)
                        
internals->active_slaves[internals->active_slave_count++] =
                                        slave_port_id;
-               }
        }
-
        return 0;

-err_add:
-       RTE_LOG(ERR, PMD, "Failed to add port %d as slave\n", slave_port_id);
-       return -1;
-
 }

+
 int
-rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)
+rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id)
 {
+       struct rte_eth_dev *bonded_eth_dev;
        struct bond_dev_private *internals;
-       struct slave_conf *slave_conf;

-       int i;
-       int pos = -1;
+       int retval;

        /* Verify that port id's are valid bonded and slave ports */
        if (valid_bonded_port_id(bonded_port_id) != 0)
-               goto err_del;
+               return -1;
+
+       bonded_eth_dev = &rte_eth_devices[bonded_port_id];
+       internals = bonded_eth_dev->data->dev_private;
+
+       rte_spinlock_lock(&internals->lock);
+
+       retval = __eth_bond_slave_add_lock_free(bonded_port_id, slave_port_id);
+
+       rte_spinlock_unlock(&internals->lock);
+
+       return retval;
+}
+
+
+static int
+__eth_bond_slave_remove_lock_free(uint8_t bonded_port_id, uint8_t 
slave_port_id)
+{
+       struct bond_dev_private *internals;
+
+       int i, slave_idx = -1;

        if (valid_slave_port_id(slave_port_id) != 0)
-               goto err_del;
+               return -1;

        internals = rte_eth_devices[bonded_port_id].data->dev_private;

        /* first remove from active slave list */
        for (i = 0; i < internals->active_slave_count; i++) {
                if (internals->active_slaves[i] == slave_port_id)
-                       pos = i;
+                       slave_idx = i;

                /* shift active slaves up active array list */
-               if (pos >= 0 && i < (internals->active_slave_count - 1))
+               if (slave_idx >= 0 && i < (internals->active_slave_count - 1))
                        internals->active_slaves[i] = 
internals->active_slaves[i+1];
        }

-       if (pos >= 0)
+       if (slave_idx >= 0)
                internals->active_slave_count--;

-       pos = -1;
-       /* now remove from slave list */
-       for (i = 0; i < internals->slave_count; i++) {
-               if (internals->slaves[i] == slave_port_id)
-                       pos = i;
+       slave_idx = -1;
+       /* now find in slave list */
+       for (i = 0; i < internals->slave_count; i++)
+               if (internals->slaves[i].port_id == slave_port_id) {
+                       slave_idx = i;
+                       break;
+               }

-               /* shift slaves up list */
-               if (pos >= 0 && i < internals->slave_count)
-                       internals->slaves[i] = internals->slaves[i+1];
+       if (slave_idx < 0) {
+               RTE_BOND_LOG(ERR, "Couldn't find slave in port list, slave 
count %d",
+                               internals->slave_count);
+               return -1;
        }

-       if (pos < 0)
-               goto err_del;
-
        /* Un-register link status change callback with bonded device pointer as
         * argument*/
        rte_eth_dev_callback_unregister(slave_port_id, RTE_ETH_EVENT_INTR_LSC,
@@ -422,13 +428,10 @@ rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t 
slave_port_id)
                        &rte_eth_devices[bonded_port_id].data->port_id);

        /* Restore original MAC address of slave device */
-       slave_conf = slave_config_get(internals, slave_port_id);
+       mac_address_set(&rte_eth_devices[slave_port_id],
+                       &(internals->slaves[slave_idx].persisted_mac_addr));

-       mac_address_set(&rte_eth_devices[slave_port_id], 
&(slave_conf->mac_addr));
-
-       slave_config_clear(internals, &rte_eth_devices[slave_port_id]);
-
-       internals->slave_count--;
+       slave_remove(internals, &rte_eth_devices[slave_port_id]);

        /*  first slave in the active list will be the primary by default,
         *  otherwise use first device in list */
@@ -436,7 +439,7 @@ rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t 
slave_port_id)
                if (internals->active_slave_count > 0)
                        internals->current_primary_port = 
internals->active_slaves[0];
                else if (internals->slave_count > 0)
-                       internals->current_primary_port = internals->slaves[0];
+                       internals->current_primary_port = 
internals->slaves[0].port_id;
                else
                        internals->primary_port = 0;
        }
@@ -454,12 +457,28 @@ rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t 
slave_port_id)
        }

        return 0;
+}

-err_del:
-       RTE_LOG(ERR, PMD,
-                       "Cannot remove slave device (not present in bonded 
device)\n");
-       return -1;
+int
+rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+       struct rte_eth_dev *bonded_eth_dev;
+       struct bond_dev_private *internals;
+       int retval;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       bonded_eth_dev = &rte_eth_devices[bonded_port_id];
+       internals = bonded_eth_dev->data->dev_private;
+
+       rte_spinlock_lock(&internals->lock);
+
+       retval = __eth_bond_slave_remove_lock_free(bonded_port_id, 
slave_port_id);
+
+       rte_spinlock_unlock(&internals->lock);

+       return retval;
 }

 int
@@ -524,6 +543,7 @@ int
 rte_eth_bond_slaves_get(uint8_t bonded_port_id, uint8_t slaves[], uint8_t len)
 {
        struct bond_dev_private *internals;
+       int i;

        if (valid_bonded_port_id(bonded_port_id) != 0)
                return -1;
@@ -536,10 +556,10 @@ rte_eth_bond_slaves_get(uint8_t bonded_port_id, uint8_t 
slaves[], uint8_t len)
        if (internals->slave_count > len)
                return -1;

-       memcpy(slaves, internals->slaves, internals->slave_count);
+       for (i = 0; i < internals->slave_count; i++)
+               slaves[i] = internals->slaves[i].port_id;

        return internals->slave_count;
-
 }

 int
@@ -605,13 +625,13 @@ rte_eth_bond_mac_address_reset(uint8_t bonded_port_id)
        internals->user_defined_mac = 0;

        if (internals->slave_count > 0) {
-               struct slave_conf *conf;
-               conf = slave_config_get(internals, internals->primary_port);
-
                /* Set MAC Address of Bonded Device */
-               if (mac_address_set(bonded_eth_dev, &conf->mac_addr) != 0)
+               if (mac_address_set(bonded_eth_dev,
+                               
&internals->slaves[internals->primary_port].persisted_mac_addr)
+                               != 0) {
+                       RTE_BOND_LOG(ERR, "Failed to set MAC address on bonded 
device");
                        return -1;
-
+               }
                /* Update all slave devices MAC addresses */
                return mac_address_slaves_update(bonded_eth_dev);
        }
@@ -654,3 +674,88 @@ rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id)

        return internals->balance_xmit_policy;
 }
+
+
+int
+rte_eth_bond_link_monitoring_set(uint8_t bonded_port_id, uint32_t internal_ms)
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+       internals->link_status_polling_interval_ms = internal_ms;
+
+       return 0;
+}
+
+int
+rte_eth_bond_link_monitoring_get(uint8_t bonded_port_id)
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+       return internals->link_status_polling_interval_ms;
+}
+
+int
+rte_eth_bond_link_down_prop_delay_set(uint8_t bonded_port_id, uint32_t 
delay_ms)
+
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+       internals->link_down_delay_ms = delay_ms;
+
+       return 0;
+}
+
+int
+rte_eth_bond_link_down_prop_delay_get(uint8_t bonded_port_id)
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+       return internals->link_down_delay_ms;
+}
+
+
+int
+rte_eth_bond_link_up_prop_delay_set(uint8_t bonded_port_id, uint32_t delay_ms)
+
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+       internals->link_up_delay_ms = delay_ms;
+
+       return 0;
+}
+
+int
+rte_eth_bond_link_up_prop_delay_get(uint8_t bonded_port_id)
+{
+       struct bond_dev_private *internals;
+
+       if (valid_bonded_port_id(bonded_port_id) != 0)
+               return -1;
+
+       internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+       return internals->link_up_delay_ms;
+}
diff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c 
b/lib/librte_pmd_bond/rte_eth_bond_args.c
index 11d9816..bbbc69b 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_args.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c
@@ -118,7 +118,7 @@ parse_port_id(const char *port_str)
        }

        if (port_id < 0 || port_id > RTE_MAX_ETHPORTS) {
-               RTE_LOG(ERR, PMD, "Invalid slave port value (%s) specified.\n",
+               RTE_BOND_LOG(ERR, "Slave port specified (%s) outside expected 
range",
                                port_str);
                return -1;
        }
@@ -138,9 +138,10 @@ bond_ethdev_parse_slave_port_kvarg(const char *key 
__rte_unused,

        if (strcmp(key, PMD_BOND_SLAVE_PORT_KVARG) == 0) {
                int port_id = parse_port_id(value);
-               if (port_id < 0)
+               if (port_id < 0) {
+                       RTE_BOND_LOG(ERR, "Invalid slave port value (%s) 
specified", value);
                        return -1;
-               else
+               } else
                        slave_ports->slaves[slave_ports->slave_count++] =
                                        (uint8_t)port_id;
        }
@@ -172,6 +173,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key 
__rte_unused,
        case BONDING_MODE_BROADCAST:
                return 0;
        default:
+               RTE_BOND_LOG(ERR, "Invalid slave mode value (%s) specified", 
value);
                return -1;
        }
 }
@@ -191,7 +193,7 @@ bond_ethdev_parse_socket_id_kvarg(const char *key 
__rte_unused,
        if (*endptr != 0 || errno != 0)
                return -1;

-       /* validate mode value */
+       /* validate socket id value */
        if (socket_id >= 0 && socket_id < number_of_sockets()) {
                *(uint8_t *)extra_args = (uint8_t)socket_id;
                return 0;
@@ -250,3 +252,23 @@ bond_ethdev_parse_bond_mac_addr_kvarg(const char *key 
__rte_unused,
        /* Parse MAC */
        return cmdline_parse_etheraddr(NULL, value, extra_args);
 }
+
+int
+bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,
+               const char *value, void *extra_args)
+{
+       uint32_t time_ms;
+       char *endptr;
+
+       if (value == NULL || extra_args == NULL)
+               return -1;
+
+       errno = 0;
+       time_ms = (uint32_t)strtol(value, &endptr, 10);
+       if (*endptr != 0 || errno != 0)
+               return -1;
+
+       *(uint32_t *)extra_args = time_ms;
+
+       return 0;
+}
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c 
b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index 2215afe..2a953d1 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -40,6 +40,7 @@
 #include <rte_devargs.h>
 #include <rte_kvargs.h>
 #include <rte_dev.h>
+#include <rte_alarm.h>

 #include "rte_eth_bond.h"
 #include "rte_eth_bond_private.h"
@@ -454,16 +455,16 @@ mac_address_set(struct rte_eth_dev *eth_dev, struct 
ether_addr *new_mac_addr)
        mac_addr = eth_dev->data->mac_addrs;

        if (eth_dev == NULL) {
-               RTE_LOG(ERR, PMD, "%s: NULL pointer eth_dev specified\n", 
__func__);
+               RTE_BOND_LOG(ERR,  "NULL pointer eth_dev specified");
                return -1;
        }

        if (new_mac_addr == NULL) {
-               RTE_LOG(ERR, PMD, "%s: NULL pointer MAC specified\n", __func__);
+               RTE_BOND_LOG(ERR, "NULL pointer MAC specified");
                return -1;
        }

-       /* if new MAC is different to current MAC then update */
+       /* If new MAC is different to current MAC then update */
        if (memcmp(mac_addr, new_mac_addr, sizeof(*mac_addr)) != 0)
                memcpy(mac_addr, new_mac_addr, sizeof(*mac_addr));

@@ -485,11 +486,10 @@ mac_address_slaves_update(struct rte_eth_dev 
*bonded_eth_dev)
        case BONDING_MODE_BALANCE:
        case BONDING_MODE_BROADCAST:
                for (i = 0; i < internals->slave_count; i++) {
-                       if 
(mac_address_set(&rte_eth_devices[internals->slaves[i]],
+                       if 
(mac_address_set(&rte_eth_devices[internals->slaves[i].port_id],
                                        bonded_eth_dev->data->mac_addrs)) {
-                               RTE_LOG(ERR, PMD,
-                                               "%s: Failed to update port Id 
%d MAC address\n",
-                                               __func__, internals->slaves[i]);
+                               RTE_BOND_LOG(ERR, "Failed to update port Id %d 
MAC address",
+                                               internals->slaves[i].port_id);
                                return -1;
                        }
                }
@@ -497,23 +497,20 @@ mac_address_slaves_update(struct rte_eth_dev 
*bonded_eth_dev)
        case BONDING_MODE_ACTIVE_BACKUP:
        default:
                for (i = 0; i < internals->slave_count; i++) {
-                       if (internals->slaves[i] == 
internals->current_primary_port) {
+                       if (internals->slaves[i].port_id ==
+                                       internals->current_primary_port) {
                                if 
(mac_address_set(&rte_eth_devices[internals->primary_port],
                                                
bonded_eth_dev->data->mac_addrs)) {
-                                       RTE_LOG(ERR, PMD,
-                                                       "%s: Failed to update 
port Id %d MAC address\n",
-                                                       __func__, 
internals->current_primary_port);
+                                       RTE_BOND_LOG(ERR, "Failed to update 
port Id %d MAC address",
+                                                       
internals->current_primary_port);
+                                       return -1;
                                }
                        } else {
-                               struct slave_conf *conf =
-                                               slave_config_get(internals, 
internals->slaves[i]);
-
-                               if 
(mac_address_set(&rte_eth_devices[internals->slaves[i]],
-                                               &conf->mac_addr)) {
-                                       RTE_LOG(ERR, PMD,
-                                                       "%s: Failed to update 
port Id %d MAC address\n",
-                                                       __func__, 
internals->slaves[i]);
-
+                               if (mac_address_set(
+                                               
&rte_eth_devices[internals->slaves[i].port_id],
+                                               
&internals->slaves[i].persisted_mac_addr)) {
+                                       RTE_BOND_LOG(ERR, "Failed to update 
port Id %d MAC address",
+                                                       
internals->slaves[i].port_id);
                                        return -1;
                                }
                        }
@@ -563,34 +560,39 @@ slave_configure(struct rte_eth_dev *bonded_eth_dev,
        struct bond_rx_queue *bd_rx_q;
        struct bond_tx_queue *bd_tx_q;

-       int q_id;
+       int errval, q_id;

        /* Stop slave */
        rte_eth_dev_stop(slave_eth_dev->data->port_id);

-       /* Enable interrupts on slave device */
-       slave_eth_dev->data->dev_conf.intr_conf.lsc = 1;
+       /* Enable interrupts on slave device if supported */
+       if (slave_eth_dev->driver->pci_drv.drv_flags & RTE_PCI_DRV_INTR_LSC)
+               slave_eth_dev->data->dev_conf.intr_conf.lsc = 1;

-       if (rte_eth_dev_configure(slave_eth_dev->data->port_id,
+       /* Configure device */
+       errval = rte_eth_dev_configure(slave_eth_dev->data->port_id,
                        bonded_eth_dev->data->nb_rx_queues,
                        bonded_eth_dev->data->nb_tx_queues,
-                       &(slave_eth_dev->data->dev_conf)) != 0) {
-               RTE_LOG(ERR, PMD, "Cannot configure slave device: port=%u\n",
-                               slave_eth_dev->data->port_id);
-               return -1;
+                       &(slave_eth_dev->data->dev_conf));
+       if (errval != 0) {
+               RTE_BOND_LOG(ERR, "Cannot configure slave device: port %u , err 
(%d)",
+                               slave_eth_dev->data->port_id, errval);
+               return errval;
        }

        /* Setup Rx Queues */
        for (q_id = 0; q_id < bonded_eth_dev->data->nb_rx_queues; q_id++) {
                bd_rx_q = (struct bond_rx_queue 
*)bonded_eth_dev->data->rx_queues[q_id];

-               if (rte_eth_rx_queue_setup(slave_eth_dev->data->port_id, q_id,
+               errval = rte_eth_rx_queue_setup(slave_eth_dev->data->port_id, 
q_id,
                                bd_rx_q->nb_rx_desc,
                                
rte_eth_dev_socket_id(slave_eth_dev->data->port_id),
-                               &(bd_rx_q->rx_conf), bd_rx_q->mb_pool) != 0) {
-                       RTE_LOG(ERR, PMD, "rte_eth_rx_queue_setup: port=%d 
queue_id %d\n",
-                                       slave_eth_dev->data->port_id, q_id);
-                       return -1;
+                               &(bd_rx_q->rx_conf), bd_rx_q->mb_pool);
+               if (errval != 0) {
+                       RTE_BOND_LOG(ERR,
+                                       "rte_eth_rx_queue_setup: port=%d 
queue_id %d, err (%d)",
+                                       slave_eth_dev->data->port_id, q_id, 
errval);
+                       return errval;
                }
        }

@@ -598,69 +600,77 @@ slave_configure(struct rte_eth_dev *bonded_eth_dev,
        for (q_id = 0; q_id < bonded_eth_dev->data->nb_tx_queues; q_id++) {
                bd_tx_q = (struct bond_tx_queue 
*)bonded_eth_dev->data->tx_queues[q_id];

-               if (rte_eth_tx_queue_setup(slave_eth_dev->data->port_id, q_id,
+               errval = rte_eth_tx_queue_setup(slave_eth_dev->data->port_id, 
q_id,
                                bd_tx_q->nb_tx_desc,
                                
rte_eth_dev_socket_id(slave_eth_dev->data->port_id),
-                               &bd_tx_q->tx_conf) != 0) {
-                       RTE_LOG(ERR, PMD, "rte_eth_tx_queue_setup: port=%d 
queue_id %d\n",
-                                       slave_eth_dev->data->port_id, q_id);
-                       return -1;
+                               &bd_tx_q->tx_conf);
+               if (errval != 0) {
+                       RTE_BOND_LOG(ERR,
+                                       "rte_eth_tx_queue_setup: port=%d 
queue_id %d, err (%d)",
+                                       slave_eth_dev->data->port_id, q_id, 
errval);
+                       return errval;
                }
        }

        /* Start device */
-       if (rte_eth_dev_start(slave_eth_dev->data->port_id) != 0) {
-               RTE_LOG(ERR, PMD, "rte_eth_dev_start: port=%u\n",
-                               slave_eth_dev->data->port_id);
+       errval = rte_eth_dev_start(slave_eth_dev->data->port_id);
+       if (errval != 0) {
+               RTE_BOND_LOG(ERR, "rte_eth_dev_start: port=%u, err (%d)",
+                               slave_eth_dev->data->port_id, errval);
                return -1;
        }

        return 0;
 }

-struct slave_conf *
-slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id)
-{
-       int i;
-
-       for (i = 0; i < internals->slave_count; i++) {
-               if (internals->presisted_slaves_conf[i].port_id == 
slave_port_id)
-                       return &internals->presisted_slaves_conf[i];
-       }
-       return NULL;
-}
-
 void
-slave_config_clear(struct bond_dev_private *internals,
+slave_remove(struct bond_dev_private *internals,
                struct rte_eth_dev *slave_eth_dev)
 {
        int i, found = 0;

        for (i = 0; i < internals->slave_count; i++) {
-               if (internals->presisted_slaves_conf[i].port_id ==
-                               slave_eth_dev->data->port_id) {
+               if (internals->slaves[i].port_id ==     
slave_eth_dev->data->port_id)
                        found = 1;
-                       memset(&internals->presisted_slaves_conf[i], 0,
-                                       
sizeof(internals->presisted_slaves_conf[i]));
-               }
-               if (found && i < (internals->slave_count - 1)) {
-                       memcpy(&internals->presisted_slaves_conf[i],
-                                       &internals->presisted_slaves_conf[i+1],
-                                       
sizeof(internals->presisted_slaves_conf[i]));
-               }
+
+               if (found && i < (internals->slave_count - 1))
+                       memcpy(&internals->slaves[i], &internals->slaves[i+1],
+                                       sizeof(internals->slaves[i]));
        }
+
+       internals->slave_count--;
 }

+static void
+bond_ethdev_slave_link_status_change_monitor(void *cb_arg);
+
 void
-slave_config_store(struct bond_dev_private *internals,
+slave_add(struct bond_dev_private *internals,
                struct rte_eth_dev *slave_eth_dev)
 {
-       struct slave_conf *presisted_slave_conf =
-                       
&internals->presisted_slaves_conf[internals->slave_count];
+       struct bond_slave_details *slave_details =
+                       &internals->slaves[internals->slave_count];
+
+       slave_details->port_id = slave_eth_dev->data->port_id;
+       slave_details->last_link_status = 0;
+
+       /* If slave device doesn't support interrupts then we need to enabled
+        * polling to monitor link status */
+       if (!(slave_eth_dev->pci_dev->driver->drv_flags & 
RTE_PCI_DRV_INTR_LSC)) {
+               slave_details->link_status_poll_enabled = 1;
+
+               if (!internals->link_status_polling_enabled) {
+                       internals->link_status_polling_enabled = 1;

-       presisted_slave_conf->port_id = slave_eth_dev->data->port_id;
+                       
rte_eal_alarm_set(internals->link_status_polling_interval_ms * 1000,
+                                       
bond_ethdev_slave_link_status_change_monitor,
+                                       (void 
*)&rte_eth_devices[internals->port_id]);
+               }
+       }

-       memcpy(&(presisted_slave_conf->mac_addr), 
slave_eth_dev->data->mac_addrs,
+       slave_details->link_status_wait_to_complete = 0;
+
+       memcpy(&(slave_details->persisted_mac_addr), 
slave_eth_dev->data->mac_addrs,
                        sizeof(struct ether_addr));
 }

@@ -691,31 +701,33 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)

        /* slave eth dev will be started by bonded device */
        if (valid_bonded_ethdev(eth_dev)) {
-               RTE_LOG(ERR, PMD,
-                               "%s: user tried to explicitly start a slave 
eth_dev (%d) of the bonded eth_dev\n",
-                               __func__, eth_dev->data->port_id);
+               RTE_BOND_LOG(ERR, "User tried to explicitly start a slave 
eth_dev (%d)",
+                               eth_dev->data->port_id);
                return -1;
        }

-       eth_dev->data->dev_link.link_status = 1;
+       eth_dev->data->dev_link.link_status = 0;
        eth_dev->data->dev_started = 1;

        internals = eth_dev->data->dev_private;

        if (internals->slave_count == 0) {
-               RTE_LOG(ERR, PMD,
-                               "%s: Cannot start port since there are no slave 
devices\n",
-                               __func__);
+               RTE_BOND_LOG(ERR, "Cannot start port since there are no slave 
devices");
                return -1;
        }

        if (internals->user_defined_mac == 0) {
-               struct slave_conf *conf = slave_config_get(internals,
-                               internals->primary_port);
+               struct ether_addr *new_mac_addr = NULL;
+
+               for (i = 0; i < internals->slave_count; i++)
+                       if (internals->slaves[i].port_id == 
internals->primary_port)
+                               new_mac_addr = 
&internals->slaves[i].persisted_mac_addr;
+
+               if (new_mac_addr == NULL)
+                       return -1;

-               if (mac_address_set(eth_dev, &(conf->mac_addr)) != 0) {
-                       RTE_LOG(ERR, PMD,
-                                       "bonded port (%d) failed to update mac 
address",
+               if (mac_address_set(eth_dev, new_mac_addr) != 0) {
+                       RTE_BOND_LOG(ERR, "bonded port (%d) failed to update 
MAC address",
                                        eth_dev->data->port_id);
                        return -1;
                }
@@ -731,11 +743,11 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)

        /* Reconfigure each slave device if starting bonded device */
        for (i = 0; i < internals->slave_count; i++) {
-               if (slave_configure(eth_dev, 
&(rte_eth_devices[internals->slaves[i]]))
-                               != 0) {
-                       RTE_LOG(ERR, PMD, "bonded port "
-                                       "(%d) failed to reconfigure slave 
device (%d)\n)",
-                                       eth_dev->data->port_id, 
internals->slaves[i]);
+               if (slave_configure(eth_dev,
+                               
&(rte_eth_devices[internals->slaves[i].port_id])) != 0) {
+                       RTE_BOND_LOG(ERR,
+                                       "bonded port (%d) failed to reconfigure 
slave device (%d)",
+                                       eth_dev->data->port_id, 
internals->slaves[i].port_id);
                        return -1;
                }
        }
@@ -752,6 +764,7 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)
        struct bond_dev_private *internals = eth_dev->data->dev_private;

        internals->active_slave_count = 0;
+       internals->link_status_polling_enabled = 0;

        eth_dev->data->dev_link.link_status = 0;
        eth_dev->data->dev_started = 0;
@@ -845,6 +858,65 @@ bond_ethdev_tx_queue_release(void *queue)
        rte_free(queue);
 }

+
+static void
+bond_ethdev_slave_link_status_change_monitor(void *cb_arg)
+{
+       struct rte_eth_dev *bonded_ethdev, *slave_ethdev;
+       struct bond_dev_private *internals;
+
+       /* Default value for polling slave found is true as we don't want to
+        * disable the polling thread if we cannot get the lock */
+       int i, polling_slave_found = 1;
+
+       if (cb_arg == NULL)
+               return;
+
+       bonded_ethdev = (struct rte_eth_dev *)cb_arg;
+       internals = (struct bond_dev_private *)bonded_ethdev->data->dev_private;
+
+       if (!bonded_ethdev->data->dev_started ||
+               !internals->link_status_polling_enabled)
+               return;
+
+       /* If device is currently being configured then don't check slaves link
+        * status, wait until next period */
+       if (rte_spinlock_trylock(&internals->lock)){
+               if (internals->slave_count > 0)
+                       polling_slave_found = 0;
+
+               for (i = 0; i < internals->slave_count; i++) {
+                       if (!internals->slaves[i].link_status_poll_enabled)
+                               continue;
+
+                       slave_ethdev = 
&rte_eth_devices[internals->slaves[i].port_id];
+                       polling_slave_found = 1;
+
+                       /* Update slave link status */
+                       (*slave_ethdev->dev_ops->link_update)(slave_ethdev,
+                                       
internals->slaves[i].link_status_wait_to_complete);
+
+                       /* if link status has changed since last checked then 
call lsc
+                        * event callback */
+                       if (slave_ethdev->data->dev_link.link_status !=
+                                       internals->slaves[i].last_link_status) {
+                               internals->slaves[i].last_link_status =
+                                               
slave_ethdev->data->dev_link.link_status;
+
+                               
bond_ethdev_lsc_event_callback(internals->slaves[i].port_id,
+                                               RTE_ETH_EVENT_INTR_LSC,
+                                               &bonded_ethdev->data->port_id);
+                       }
+               }
+               rte_spinlock_unlock(&internals->lock);
+       }
+
+       if (polling_slave_found)
+               /* Set alarm to continue monitoring link status of slave 
ethdev's */
+               rte_eal_alarm_set(internals->link_status_polling_interval_ms * 
1000,
+                               bond_ethdev_slave_link_status_change_monitor, 
cb_arg);
+}
+
 static int
 bond_ethdev_link_update(struct rte_eth_dev *bonded_eth_dev,
                int wait_to_complete)
@@ -888,7 +960,7 @@ bond_ethdev_stats_get(struct rte_eth_dev *dev, struct 
rte_eth_stats *stats)
        memset(stats, 0, sizeof(*stats));

        for (i = 0; i < internals->slave_count; i++) {
-               rte_eth_stats_get(internals->slaves[i], &slave_stats);
+               rte_eth_stats_get(internals->slaves[i].port_id, &slave_stats);

                stats->ipackets += slave_stats.ipackets;
                stats->opackets += slave_stats.opackets;
@@ -914,7 +986,7 @@ bond_ethdev_stats_reset(struct rte_eth_dev *dev)
        int i;

        for (i = 0; i < internals->slave_count; i++)
-               rte_eth_stats_reset(internals->slaves[i]);
+               rte_eth_stats_reset(internals->slaves[i].port_id);
 }

 static void
@@ -931,7 +1003,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
        case BONDING_MODE_BALANCE:
        case BONDING_MODE_BROADCAST:
                for (i = 0; i < internals->slave_count; i++)
-                       rte_eth_promiscuous_enable(internals->slaves[i]);
+                       
rte_eth_promiscuous_enable(internals->slaves[i].port_id);
                break;
        /* Promiscuous mode is propagated only to primary slave */
        case BONDING_MODE_ACTIVE_BACKUP:
@@ -955,7 +1027,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
        case BONDING_MODE_BALANCE:
        case BONDING_MODE_BROADCAST:
                for (i = 0; i < internals->slave_count; i++)
-                       rte_eth_promiscuous_disable(internals->slaves[i]);
+                       
rte_eth_promiscuous_disable(internals->slaves[i].port_id);
                break;
        /* Promiscuous mode is propagated only to primary slave */
        case BONDING_MODE_ACTIVE_BACKUP:
@@ -964,6 +1036,16 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
        }
 }

+static void
+bond_ethdev_delayed_lsc_propagation(void *arg)
+{
+       if (arg == NULL)
+               return;
+
+       _rte_eth_dev_callback_process((struct rte_eth_dev *)arg,
+                       RTE_ETH_EVENT_INTR_LSC);
+}
+
 void
 bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,
                void *param)
@@ -992,7 +1074,7 @@ bond_ethdev_lsc_event_callback(uint8_t port_id, enum 
rte_eth_event_type type,

        /* verify that port_id is a valid slave of bonded port */
        for (i = 0; i < internals->slave_count; i++) {
-               if (internals->slaves[i] == port_id) {
+               if (internals->slaves[i].port_id == port_id) {
                        valid_slave = 1;
                        break;
                }
@@ -1061,8 +1143,32 @@ bond_ethdev_lsc_event_callback(uint8_t port_id, enum 
rte_eth_event_type type,
                }
        }

-       if (lsc_flag)
-               _rte_eth_dev_callback_process(bonded_eth_dev, 
RTE_ETH_EVENT_INTR_LSC);
+       if (lsc_flag) {
+               /* Cancel any possible outstanding interrupts if delays are 
enabled */
+               if (internals->link_up_delay_ms > 0 ||
+                       internals->link_down_delay_ms > 0)
+                       
rte_eal_alarm_cancel(bond_ethdev_delayed_lsc_propagation,
+                                       bonded_eth_dev);
+
+               if (bonded_eth_dev->data->dev_link.link_status) {
+                       if (internals->link_up_delay_ms > 0)
+                               rte_eal_alarm_set(internals->link_up_delay_ms * 
1000,
+                                               
bond_ethdev_delayed_lsc_propagation,
+                                               (void *)bonded_eth_dev);
+                       else
+                               _rte_eth_dev_callback_process(bonded_eth_dev,
+                                               RTE_ETH_EVENT_INTR_LSC);
+
+               } else {
+                       if (internals->link_down_delay_ms > 0)
+                               rte_eal_alarm_set(internals->link_down_delay_ms 
* 1000,
+                                               
bond_ethdev_delayed_lsc_propagation,
+                                               (void *)bonded_eth_dev);
+                       else
+                               _rte_eth_dev_callback_process(bonded_eth_dev,
+                                               RTE_ETH_EVENT_INTR_LSC);
+               }
+       }
 }

 struct eth_dev_ops default_dev_ops = {
@@ -1212,8 +1318,8 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
                }
        } else if (arg_count > 1) {
                RTE_LOG(ERR, EAL,
-                               "Transmit policy can be specified only once for 
bonded device %s\n",
-                               name);
+                               "Transmit policy can be specified only once for 
bonded device"
+                               " %s\n", name);
                return -1;
        }

@@ -1255,8 +1361,8 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
                                &bond_ethdev_parse_primary_slave_port_id_kvarg,
                                &primary_slave_port_id) < 0) {
                        RTE_LOG(INFO, EAL,
-                                       "Invalid primary slave port id 
specified for bonded device %s\n",
-                                       name);
+                                       "Invalid primary slave port id 
specified for bonded device"
+                                       " %s\n", name);
                        return -1;
                }

@@ -1270,8 +1376,97 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
                }
        } else if (arg_count > 1) {
                RTE_LOG(INFO, EAL,
-                               "Primary slave can be specified only once for 
bonded device %s\n",
-                               name);
+                               "Primary slave can be specified only once for 
bonded device"
+                               " %s\n", name);
+               return -1;
+       }
+
+       /* Parse link status monitor polling interval */
+       arg_count = rte_kvargs_count(kvlist, PMD_BOND_LSC_POLL_PERIOD_KVARG);
+       if (arg_count == 1) {
+               uint32_t lsc_poll_interval_ms;
+
+               if (rte_kvargs_process(kvlist,
+                               PMD_BOND_LSC_POLL_PERIOD_KVARG,
+                               &bond_ethdev_parse_time_ms_kvarg,
+                               &lsc_poll_interval_ms) < 0) {
+                       RTE_LOG(INFO, EAL,
+                                       "Invalid lsc polling interval value 
specified for bonded"
+                                       "device %s\n", name);
+                       return -1;
+               }
+
+               if (rte_eth_bond_link_monitoring_set(port_id, 
lsc_poll_interval_ms)
+                               != 0) {
+                       RTE_LOG(ERR, EAL,
+                                       "Failed to set lsc monitor polling 
interval (%u ms) on"
+                                       " bonded device %s\n", 
lsc_poll_interval_ms, name);
+                       return -1;
+               }
+       } else if (arg_count > 1) {
+               RTE_LOG(INFO, EAL,
+                               "LSC polling interval can be specified only 
once for bonded"
+                               "device %s\n", name);
+               return -1;
+       }
+
+       /* Parse link up interrupt propagation delay */
+       arg_count = rte_kvargs_count(kvlist, PMD_BOND_LINK_UP_PROP_DELAY_KVARG);
+       if (arg_count == 1) {
+               uint32_t link_up_delay_ms;
+
+               if (rte_kvargs_process(kvlist,
+                               PMD_BOND_LINK_UP_PROP_DELAY_KVARG,
+                               &bond_ethdev_parse_time_ms_kvarg,
+                               &link_up_delay_ms) < 0) {
+                       RTE_LOG(INFO, EAL,
+                                       "Invalid link up propagation delay 
value specified for "
+                                       "bonded device %s\n", name);
+                       return -1;
+               }
+
+               /* Set balance mode transmit policy*/
+               if (rte_eth_bond_link_up_prop_delay_set(port_id, 
link_up_delay_ms)
+                               != 0) {
+                       RTE_LOG(ERR, EAL,
+                                       "Failed to set link up propagation 
delay (%u ms) on bonded"
+                                       "device %s\n", link_up_delay_ms, name);
+                       return -1;
+               }
+       } else if (arg_count > 1) {
+               RTE_LOG(INFO, EAL,
+                               "Link up propagation delay can be specified 
only once for "
+                               "bonded device %s\n", name);
+               return -1;
+       }
+
+       /* Parse link down interrupt propagation delay */
+       arg_count = rte_kvargs_count(kvlist, 
PMD_BOND_LINK_DOWN_PROP_DELAY_KVARG);
+       if (arg_count == 1) {
+               uint32_t link_down_delay_ms;
+
+               if (rte_kvargs_process(kvlist,
+                               PMD_BOND_LINK_DOWN_PROP_DELAY_KVARG,
+                               &bond_ethdev_parse_time_ms_kvarg,
+                               &link_down_delay_ms) < 0) {
+                       RTE_LOG(INFO, EAL,
+                                       "Invalid link down propagation delay 
value specified for"
+                                       "bonded device %s\n", name);
+                       return -1;
+               }
+
+               /* Set balance mode transmit policy*/
+               if (rte_eth_bond_link_down_prop_delay_set(port_id, 
link_down_delay_ms)
+                               != 0) {
+                       RTE_LOG(ERR, EAL,
+                                       "Failed to set link down propagation 
delay (%u ms) on"
+                                       " bonded device %s\n", 
link_down_delay_ms, name);
+                       return -1;
+               }
+       } else if (arg_count > 1) {
+               RTE_LOG(INFO, EAL,
+                               "Link down propagation delay can be specified 
only once for"
+                               " bonded device %s\n", name);
                return -1;
        }

diff --git a/lib/librte_pmd_bond/rte_eth_bond_private.h 
b/lib/librte_pmd_bond/rte_eth_bond_private.h
index 1db6e4d..78f4196 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_private.h
+++ b/lib/librte_pmd_bond/rte_eth_bond_private.h
@@ -39,20 +39,27 @@ extern "C" {
 #endif

 #include <rte_ethdev.h>
+#include <rte_spinlock.h>

 #include "rte_eth_bond.h"

-#define PMD_BOND_SLAVE_PORT_KVARG              ("slave")
-#define PMD_BOND_PRIMARY_SLAVE_KVARG   ("primary")
-#define PMD_BOND_MODE_KVARG                            ("mode")
-#define PMD_BOND_XMIT_POLICY_KVARG             ("xmit_policy")
-#define PMD_BOND_SOCKET_ID_KVARG               ("socket_id")
-#define PMD_BOND_MAC_ADDR_KVARG                        ("mac")
+#define PMD_BOND_SLAVE_PORT_KVARG                      ("slave")
+#define PMD_BOND_PRIMARY_SLAVE_KVARG           ("primary")
+#define PMD_BOND_MODE_KVARG                                    ("mode")
+#define PMD_BOND_XMIT_POLICY_KVARG                     ("xmit_policy")
+#define PMD_BOND_SOCKET_ID_KVARG                       ("socket_id")
+#define PMD_BOND_MAC_ADDR_KVARG                                ("mac")
+#define PMD_BOND_LSC_POLL_PERIOD_KVARG         ("lsc_poll_period_ms")
+#define PMD_BOND_LINK_UP_PROP_DELAY_KVARG      ("up_delay")
+#define PMD_BOND_LINK_DOWN_PROP_DELAY_KVARG    ("down_delay")

 #define PMD_BOND_XMIT_POLICY_LAYER2_KVARG      ("l2")
 #define PMD_BOND_XMIT_POLICY_LAYER23_KVARG     ("l23")
 #define PMD_BOND_XMIT_POLICY_LAYER34_KVARG     ("l34")

+#define RTE_BOND_LOG(lvl, msg, ...)            \
+       RTE_LOG(lvl, PMD, "%s(%d) - " msg "\n", __func__, __LINE__, 
##__VA_ARGS__);
+
 extern const char *pmd_bond_init_valid_arguments[];

 extern const char *driver_name;
@@ -82,27 +89,36 @@ struct bond_tx_queue {
        /**< Copy of TX configuration structure for queue */
 };

-/** Persisted Slave Configuration Structure */
-struct slave_conf {
-       uint8_t port_id;
-       /**< Port Id of slave eth_dev */
-       struct ether_addr mac_addr;
-       /**< Slave eth_dev original MAC address */
-};
+
 /** Bonded slave devices structure */
 struct bond_ethdev_slave_ports {
        uint8_t slaves[RTE_MAX_ETHPORTS];       /**< Slave port id array */
        uint8_t slave_count;                            /**< Number of slaves */
 };

+struct bond_slave_details {
+       uint8_t port_id;
+
+       uint8_t link_status_poll_enabled;
+       uint8_t link_status_wait_to_complete;
+       uint8_t last_link_status;
+
+       /**< Port Id of slave eth_dev */
+       struct ether_addr persisted_mac_addr;
+};
+
 /** Link Bonding PMD device private configuration Structure */
 struct bond_dev_private {
+       uint8_t port_id;                                        /**< Port Id of 
Bonded Port */
        uint8_t mode;                                           /**< Link 
Bonding Mode */

+       rte_spinlock_t lock;
+
        uint8_t primary_port;                           /**< Primary Slave Port 
*/
        uint8_t current_primary_port;           /**< Primary Slave Port */
        uint8_t user_defined_primary_port;
        /**< Flag for whether primary port is user defined or not */
+
        uint8_t balance_xmit_policy;
        /**< Transmit policy - l2 / l23 / l34 for operation in balance mode */
        uint8_t user_defined_mac;
@@ -110,19 +126,23 @@ struct bond_dev_private {
        uint8_t promiscuous_en;
        /**< Enabled/disable promiscuous mode on slave devices */
        uint8_t link_props_set;
-       /**< Bonded eth_dev link properties set */
+       /**< flag to denote if the link properties are set */
+
+       uint8_t link_status_polling_enabled;
+       uint32_t link_status_polling_interval_ms;
+
+       uint32_t link_down_delay_ms;
+       uint32_t link_up_delay_ms;

        uint16_t nb_rx_queues;                  /**< Total number of rx queues 
*/
        uint16_t nb_tx_queues;                  /**< Total number of tx queues*/

-       uint8_t slave_count;                    /**< Number of active slaves */
-       uint8_t active_slave_count;             /**< Number of slaves */
-
+       uint8_t active_slave_count;             /**< Number of active slaves */
        uint8_t active_slaves[RTE_MAX_ETHPORTS];        /**< Active slave list 
*/
-       uint8_t slaves[RTE_MAX_ETHPORTS];                       /**< Slave list 
*/

-       /** Persisted configuration of slaves */
-       struct slave_conf presisted_slaves_conf[RTE_MAX_ETHPORTS];
+       uint8_t slave_count;                    /**< Number of bonded slaves */
+       struct bond_slave_details slaves[RTE_MAX_ETHPORTS];
+       /**< Arary of bonded slaves details */

        struct rte_kvargs *kvlist;
 };
@@ -168,16 +188,13 @@ slave_configure(struct rte_eth_dev *bonded_eth_dev,
                struct rte_eth_dev *slave_eth_dev);

 void
-slave_config_clear(struct bond_dev_private *internals,
+slave_remove(struct bond_dev_private *internals,
                struct rte_eth_dev *slave_eth_dev);

 void
-slave_config_store(struct bond_dev_private *internals,
+slave_add(struct bond_dev_private *internals,
                struct rte_eth_dev *slave_eth_dev);

-struct slave_conf *
-slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id);
-
 void
 bond_ethdev_primary_set(struct bond_dev_private *internals,
                uint8_t slave_port_id);
@@ -210,6 +227,10 @@ int
 bond_ethdev_parse_bond_mac_addr_kvarg(const char *key __rte_unused,
                const char *value, void *extra_args);

+int
+bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,
+               const char *value, void *extra_args);
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.7.12.2

Reply via email to