[dpdk-dev,v3,4/5] bond: lsc polling support
diff mbox

Message ID 1411478290-28807-5-git-send-email-declan.doherty@intel.com
State Superseded, archived
Headers show

Commit Message

Doherty, Declan Sept. 23, 2014, 1:18 p.m. UTC
Adds link status polling functionality to bonding device as well as API
to set polling interval and link up / down propagation delay.
Also contains unit tests for testing polling functionailty.


Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 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     |  309 +++++++++++++++--------
 lib/librte_pmd_bond/rte_eth_bond_args.c    |   30 ++-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  387 +++++++++++++++++++++-------
 lib/librte_pmd_bond/rte_eth_bond_private.h |   71 ++++--
 9 files changed, 861 insertions(+), 346 deletions(-)

Comments

Konstantin Ananyev Sept. 24, 2014, 1:16 p.m. UTC | #1
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Declan Doherty
> Sent: Tuesday, September 23, 2014 2:18 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v3 4/5] bond: lsc polling support
> 
> Adds link status polling functionality to bonding device as well as API
> to set polling interval and link up / down propagation delay.
> Also contains unit tests for testing polling functionailty.
> 
> 
> Signed-off-by: Declan Doherty <declan.doherty@intel.com>
> ---
>  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     |  309 +++++++++++++++--------
>  lib/librte_pmd_bond/rte_eth_bond_args.c    |   30 ++-
>  lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  387 +++++++++++++++++++++-------
>  lib/librte_pmd_bond/rte_eth_bond_private.h |   71 ++++--
>  9 files changed, 861 insertions(+), 346 deletions(-)
> 
> --
> 1.7.4.1

Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>

Patch
diff mbox

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..c690ceb 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,9 +217,8 @@  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;
 	}
 
@@ -228,15 +226,21 @@  rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
 	internals->balance_xmit_policy = BALANCE_XMIT_POLICY_LAYER2;
 	internals->user_defined_mac = 0;
 	internals->link_props_set = 0;
+
+	rte_spinlock_init(&internals->lock);
+
+	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 +257,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 +267,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 +313,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 +331,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 +347,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 +427,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], &(slave_conf->mac_addr));
+	mac_address_set(&rte_eth_devices[slave_port_id],
+			&(internals->slaves[slave_idx].persisted_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 +438,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 +456,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
@@ -605,13 +623,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 +672,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 6018feb..6d0fb1b 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;
 				}
 			}
@@ -560,37 +557,47 @@  int
 slave_configure(struct rte_eth_dev *bonded_eth_dev,
 		struct rte_eth_dev *slave_eth_dev)
 {
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
 	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;
+	else
+		internals->link_status_polling_enabled = 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 +605,65 @@  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--;
 }
 
 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_polling_enabled = 1;
 
-	presisted_slave_conf->port_id = slave_eth_dev->data->port_id;
+	slave_details->link_status_wait_to_complete = 0;
 
-	memcpy(&(presisted_slave_conf->mac_addr), slave_eth_dev->data->mac_addrs,
+	memcpy(&(slave_details->persisted_mac_addr), slave_eth_dev->data->mac_addrs,
 			sizeof(struct ether_addr));
 }
 
@@ -683,6 +686,9 @@  bond_ethdev_primary_set(struct bond_dev_private *internals,
 static void
 bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev);
 
+static void
+bond_ethdev_slave_link_status_change_monitor(void *cb_arg);
+
 static int
 bond_ethdev_start(struct rte_eth_dev *eth_dev)
 {
@@ -691,31 +697,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 +739,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;
 		}
 	}
@@ -743,6 +751,12 @@  bond_ethdev_start(struct rte_eth_dev *eth_dev)
 	if (internals->user_defined_primary_port)
 		bond_ethdev_primary_set(internals, internals->primary_port);
 
+
+	if (internals->link_status_polling_enabled)
+		rte_eal_alarm_set(internals->link_status_polling_interval_ms * 1000,
+				bond_ethdev_slave_link_status_change_monitor,
+				(void *)eth_dev);
+
 	return 0;
 }
 
@@ -752,6 +766,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;
@@ -848,6 +863,57 @@  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;
+
+	int i;
+
+	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)){
+		for (i = 0; i < internals->slave_count; i++) {
+			if (internals->slaves[i].link_status_polling_enabled) {
+				slave_ethdev = &rte_eth_devices[internals->slaves[i].port_id];
+
+				/* 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);
+	}
+
+	/* 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)
@@ -891,7 +957,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;
@@ -917,7 +983,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
@@ -934,7 +1000,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:
@@ -958,7 +1024,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:
@@ -967,6 +1033,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)
@@ -995,7 +1071,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;
 		}
@@ -1064,8 +1140,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 = {
@@ -1193,8 +1293,8 @@  bond_init(const char *name, const char *params)
 		}
 	} 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;
 	}
 
@@ -1236,8 +1336,8 @@  bond_init(const char *name, const char *params)
 				&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;
 		}
 
@@ -1251,8 +1351,97 @@  bond_init(const char *name, const char *params)
 		}
 	} 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 60f1e8d..6db5144 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_polling_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 */
 };
 
 extern struct eth_dev_ops default_dev_ops;
@@ -166,16 +186,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);
@@ -208,6 +225,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