All of lore.kernel.org
 help / color / mirror / Atom feed
From: Declan Doherty <declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
To: dev-VfR2kkLFssw@public.gmane.org
Subject: [PATCH v5 7/8] bond: lsc polling support
Date: Tue, 14 Oct 2014 13:59:56 +0100	[thread overview]
Message-ID: <1413291597-27326-8-git-send-email-declan.doherty@intel.com> (raw)
In-Reply-To: <1413291597-27326-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>


Signed-off-by: Declan Doherty <declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 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 e9cf53e..490893d 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()
@@ -3709,6 +3712,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 *** */
@@ -7457,6 +7519,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 72f527e..e105c84 100644
--- a/app/test/virtual_pmd.c
+++ b/app/test/virtual_pmd.c
@@ -457,6 +457,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)
 {
@@ -504,7 +512,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;
@@ -554,7 +562,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 7f75763..7a4a647 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

  parent reply	other threads:[~2014-10-14 12:59 UTC|newest]

Thread overview: 91+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-19 13:51 [PATCH 0/6] link bonding Declan Doherty
     [not found] ` <1408456313-28812-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-08-19 13:51   ` [PATCH 1/6] bond: link status interrupt support Declan Doherty
     [not found]     ` <1408456313-28812-2-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-08-20 20:24       ` Sanford, Robert
2014-08-19 13:51   ` [PATCH 2/6] bond: removing switch statement from rx burst method Declan Doherty
     [not found]     ` <1408456313-28812-3-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-08-20 20:25       ` Sanford, Robert
2014-08-19 13:51   ` [PATCH 3/6] bond: fix naming inconsistency in tx_burst_round_robin Declan Doherty
     [not found]     ` <1408456313-28812-4-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-08-20 20:25       ` Sanford, Robert
2014-08-19 13:51   ` [PATCH 4/6] bond: free mbufs if transmission fails in bonding tx_burst functions Declan Doherty
2014-08-19 13:51   ` [PATCH 5/6] test app: adding support for generating variable sized packets Declan Doherty
2014-08-19 13:51   ` [PATCH 6/6] testpmd: adding parameter to reconfig method to set socket_id when adding new port to portlist Declan Doherty
2014-08-22  7:41   ` [PATCH 0/6] link bonding Jiajia, SunX
2014-09-01  8:31   ` [PATCH v2 " Declan Doherty
     [not found]     ` <1409560289-29558-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-09-02 13:31       ` De Lara Guarch, Pablo
2014-09-02 18:15       ` Stephen Hemminger
2014-09-01  8:31   ` [PATCH v2 1/6] bond: link status interrupt support Declan Doherty
2014-09-01  8:31   ` [PATCH v2 2/6] bond: removing switch statement from rx burst method Declan Doherty
2014-09-01  8:31   ` [PATCH v2 3/6] bond: fix naming inconsistency in tx_burst_round_robin Declan Doherty
2014-09-01  8:31   ` [PATCH v2 4/6] bond: free mbufs if transmission fails in bonding tx_burst functions Declan Doherty
     [not found]     ` <1409560289-29558-5-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-09-02  9:22       ` Doherty, Declan
     [not found]         ` <345C63BAECC1AD42A2EC8C63AFFC3ADC2737656B-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-09-02  9:31           ` Thomas Monjalon
2014-09-23 13:18       ` [PATCH v3 0/5] link bonding Declan Doherty
     [not found]         ` <1411478290-28807-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-09-23 13:18           ` [PATCH v3 1/5] bond: free mbufs if transmission fails in bonding tx_burst functions Declan Doherty
2014-09-23 13:18           ` [PATCH v3 2/5] test app: adding support for generating variable sized packet Declan Doherty
2014-09-23 13:18           ` [PATCH v3 3/5] testpmd: adding parameter to reconfig method to set socket_id when adding new port to portlist Declan Doherty
2014-09-23 13:18           ` [PATCH v3 4/5] bond: lsc polling support Declan Doherty
     [not found]             ` <1411478290-28807-5-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-09-24 13:16               ` Ananyev, Konstantin
2014-09-23 13:18           ` [PATCH v3 5/5] bond: unit test test macro refactor Declan Doherty
2014-09-01  8:31   ` [PATCH v2 5/6] test app: adding support for generating variable sized packets Declan Doherty
2014-09-01  8:31   ` [PATCH v2 6/6] testpmd: adding parameter to reconfig method to set socket_id when adding new port to portlist Declan Doherty
2014-09-30  9:57   ` [PATCH v4 0/8] link bonding Declan Doherty
     [not found]     ` <1412071079-7355-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-09-30  9:57       ` [PATCH v4 1/8] bond: link status interrupt support Declan Doherty
2014-09-30  9:57       ` [PATCH v4 2/8] bond: removing switch statement from rx burst method Declan Doherty
2014-09-30  9:57       ` [PATCH v4 3/8] bond: fix naming inconsistency in tx_burst_round_robin Declan Doherty
2014-09-30  9:57       ` [PATCH v4 4/8] bond: free mbufs if transmission fails in bonding tx_burst functions Declan Doherty
     [not found]         ` <1412071079-7355-5-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-10-13 15:29           ` De Lara Guarch, Pablo
2014-09-30  9:57       ` [PATCH v4 5/8] test app: adding support for generating variable sized packet bursts Declan Doherty
     [not found]         ` <1412071079-7355-6-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-10-24  3:22           ` Liang, Cunming
2014-09-30  9:57       ` [PATCH v4 6/8] testpmd: adding parameter to reconfig method to set socket_id when adding new port to portlist Declan Doherty
2014-09-30  9:57       ` [PATCH v4 7/8] bond: lsc polling support Declan Doherty
2014-09-30  9:57       ` [PATCH v4 8/8] bond: unit test test macro refactor Declan Doherty
2014-10-08  8:49       ` [PATCH v4 0/8] link bonding Jiajia, SunX
2014-10-09 19:20       ` De Lara Guarch, Pablo
2014-10-14 12:59       ` [PATCH v5 " Declan Doherty
     [not found]         ` <1413291597-27326-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-10-14 12:59           ` [PATCH v5 1/8] bond: link status interrupt support Declan Doherty
2014-10-14 12:59           ` [PATCH v5 2/8] bond: removing switch statement from rx burst method Declan Doherty
2014-10-14 12:59           ` [PATCH v5 3/8] bond: fix naming inconsistency in tx_burst_round_robin Declan Doherty
2014-10-14 12:59           ` [PATCH v5 4/8] bond: free mbufs if transmission fails in bonding tx_burst functions Declan Doherty
2014-10-14 12:59           ` [PATCH v5 5/8] test app: adding support for generating variable sized packet Declan Doherty
2014-10-14 12:59           ` [PATCH v5 6/8] testpmd: adding parameter to reconfig method to set socket_id when adding new port to portlist Declan Doherty
2014-10-14 12:59           ` Declan Doherty [this message]
2014-10-14 12:59           ` [PATCH v5 8/8] bond: unit test test macro refactor Declan Doherty
2014-10-14 15:59           ` [PATCH v5 0/8] link bonding De Lara Guarch, Pablo
2014-11-05  3:10           ` Jiajia, SunX
2014-11-07 12:22           ` [PATCH v6 " Declan Doherty
     [not found]             ` <1415362978-6306-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-11-07 12:22               ` [PATCH v6 1/8] bond: link status interrupt support Declan Doherty
2014-11-07 12:22               ` [PATCH v6 2/8] bond: removing switch statement from rx burst method Declan Doherty
2014-11-07 12:22               ` [PATCH v6 3/8] bond: fix naming inconsistency in tx_burst_round_robin Declan Doherty
2014-11-07 12:22               ` [PATCH v6 4/8] bond: free mbufs if transmission fails in bonding tx_burst functions Declan Doherty
2014-11-07 12:22               ` [PATCH v6 5/8] test app: adding support for generating variable sized packet Declan Doherty
2014-11-07 12:22               ` [PATCH v6 6/8] testpmd: adding parameter to reconfig method to set socket_id when adding new port to portlist Declan Doherty
2014-11-07 12:22               ` [PATCH v6 7/8] bond: lsc polling support Declan Doherty
2014-11-07 12:22               ` [PATCH v6 8/8] bond: unit test test macro refactor Declan Doherty
2014-11-07 16:40               ` [PATCH v6 0/8] link bonding De Lara Guarch, Pablo
     [not found]                 ` <E115CCD9D858EF4F90C690B0DCB4D89726834C36-kPTMFJFq+rEMvF1YICWikbfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-11-21 17:07                   ` Doherty, Declan
     [not found]                     ` <345C63BAECC1AD42A2EC8C63AFFC3ADC27422D1C-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-11-21 18:36                       ` Thomas Monjalon
2014-11-23 13:40                         ` Thomas Monjalon
2014-11-21  8:59               ` Jiajia, SunX
2014-11-24 12:27               ` [PATCH v7 0/7] " Declan Doherty
     [not found]                 ` <1416832054-24086-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-11-24 12:27                   ` [PATCH v7 1/7] bond: link status interrupt support Declan Doherty
2014-11-24 12:27                   ` [PATCH v7 2/7] bond: removing switch statement from rx burst method Declan Doherty
2014-11-24 12:27                   ` [PATCH v7 3/7] bond: fix naming inconsistency in tx_burst_round_robin Declan Doherty
2014-11-24 12:27                   ` [PATCH v7 4/7] bond: free mbufs if transmission fails in bonding tx_burst functions Declan Doherty
2014-11-24 12:27                   ` [PATCH v7 5/7] testpmd: adding parameter to reconfig method to set socket_id when adding new port to portlist Declan Doherty
2014-11-24 12:27                   ` [PATCH v7 6/7] bond: lsc polling support Declan Doherty
2014-11-24 12:27                   ` [PATCH v7 7/7] bond: unit test test macro refactor Declan Doherty
2014-11-24 15:35                   ` [PATCH v7 0/7] link bonding Thomas Monjalon
2014-11-24 16:24                     ` Doherty, Declan
     [not found]                       ` <345C63BAECC1AD42A2EC8C63AFFC3ADC274244EC-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-11-24 17:53                         ` Thomas Monjalon
2014-11-24 16:33                   ` [PATCH v8 " Declan Doherty
     [not found]                     ` <1416846822-26897-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-11-24 16:33                       ` [PATCH v8 1/7] bond: link status interrupt support Declan Doherty
2014-11-24 16:33                       ` [PATCH v8 2/7] bond: removing switch statement from rx burst method Declan Doherty
2014-11-24 16:33                       ` [PATCH v8 3/7] bond: fix naming inconsistency in tx_burst_round_robin Declan Doherty
2014-11-24 16:33                       ` [PATCH v8 4/7] bond: free mbufs if transmission fails in bonding tx_burst functions Declan Doherty
2014-11-24 16:33                       ` [PATCH v8 5/7] testpmd: adding parameter to reconfig method to set socket_id when adding new port to portlist Declan Doherty
2014-11-24 16:33                       ` [PATCH v8 6/7] bond: lsc polling support Declan Doherty
2014-11-24 16:33                       ` [PATCH v8 7/7] bond: unit test test macro refactor Declan Doherty
2014-11-24 18:32                       ` [PATCH v8 0/7] link bonding Thomas Monjalon
2014-11-24 18:51                         ` Thomas Monjalon
2014-11-24 20:54                       ` Thomas Monjalon
2014-11-25 10:56                         ` Jastrzebski, MichalX K
     [not found]                           ` <60ABE07DBB3A454EB7FAD707B4BB1582138BC9F8-kPTMFJFq+rHjxeytcECX8bfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-11-25 11:20                             ` Thomas Monjalon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1413291597-27326-8-git-send-email-declan.doherty@intel.com \
    --to=declan.doherty-ral2jqcrhueavxtiumwx3w@public.gmane.org \
    --cc=dev-VfR2kkLFssw@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.