DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/4] Link Bonding Library
@ 2014-05-28 15:32 declan.doherty
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 1/4] " declan.doherty
                   ` (7 more replies)
  0 siblings, 8 replies; 127+ messages in thread
From: declan.doherty @ 2014-05-28 15:32 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

Initial release of Link Bonding Library (lib/librte_bond) with support for 
bonding modes :
 0 - Round Robin
 1 - Active Backup
 2 - Balance l2 / l23 / l34 
 3 - Broadcast

patches split:
 1 - library + makefile changes
 2 - Unit test suite, including code to generate packet bursts for
    testing rx and tx functionality of bonded device and a
    virtual/stubbed out ethdev for use as slave ethdev in testing
 3 - Link bonding integration into testpmd, including :
     - Includes the ability to  create new bonded devices.
     - Add /remove bonding slave devices. 
     - Interogate bonded device stats/configuration
     - Change bonding modes and select balance transmit polices
 4 - Add Link Bonding Library to Doxygen


 app/test-pmd/cmdline.c            |  550 +++++
 app/test-pmd/parameters.c         |    4 +-
 app/test-pmd/testpmd.c            |   28 +-
 app/test-pmd/testpmd.h            |    2 +
 app/test/Makefile                 |    3 +
 app/test/commands.c               |    3 +
 app/test/packet_burst_generator.c |  276 +++
 app/test/packet_burst_generator.h |   85 +
 app/test/test.h                   |    1 +
 app/test/test_link_bonding.c      | 4007 +++++++++++++++++++++++++++++++++++++
 app/test/virtual_pmd.c            |  580 ++++++
 app/test/virtual_pmd.h            |   74 +
 config/common_bsdapp              |    5 +
 config/common_linuxapp            |    5 +
 doc/doxy-api-index.md             |    1 +
 doc/doxy-api.conf                 |    1 +
 lib/Makefile                      |    1 +
 lib/librte_bond/Makefile          |   28 +
 lib/librte_bond/rte_bond.c        | 1679 ++++++++++++++++
 lib/librte_bond/rte_bond.h        |  228 +++
 mk/rte.app.mk                     |    5 +
 21 files changed, 7564 insertions(+), 2 deletions(-)
 create mode 100644 app/test/packet_burst_generator.c
 create mode 100644 app/test/packet_burst_generator.h
 create mode 100644 app/test/test_link_bonding.c
 create mode 100644 app/test/virtual_pmd.c
 create mode 100644 app/test/virtual_pmd.h
 create mode 100644 lib/librte_bond/Makefile
 create mode 100644 lib/librte_bond/rte_bond.c
 create mode 100644 lib/librte_bond/rte_bond.h

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH 1/4] Link Bonding Library
  2014-05-28 15:32 [dpdk-dev] [PATCH 0/4] Link Bonding Library declan.doherty
@ 2014-05-28 15:32 ` declan.doherty
  2014-05-28 16:54   ` Shaw, Jeffrey B
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 2/4] Link bonding unit tests declan.doherty
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 127+ messages in thread
From: declan.doherty @ 2014-05-28 15:32 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

Link Bonding Library (lib/librte_bond) initial release with support for
     Mode 0 - Round Robin
     Mode 1 - Active Backup
     Mode 2 - Balance -> Supports 3 transmit polices (layer 2, layer 2+3, layer
     Mode 3 - Broadcast

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 config/common_bsdapp       |    5 +
 config/common_linuxapp     |    5 +
 lib/Makefile               |    1 +
 lib/librte_bond/Makefile   |   28 +
 lib/librte_bond/rte_bond.c | 1679 ++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_bond/rte_bond.h |  228 ++++++
 mk/rte.app.mk              |    5 +
 7 files changed, 1951 insertions(+)
 create mode 100644 lib/librte_bond/Makefile
 create mode 100644 lib/librte_bond/rte_bond.c
 create mode 100644 lib/librte_bond/rte_bond.h

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 2cc7b80..53ed8b9 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -187,6 +187,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=y
 
 #
+# Compile link bonding library
+#
+CONFIG_RTE_LIBRTE_BOND=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 62619c6..35b525a 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -211,6 +211,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=n
 
 
+#
+# Compile link bonding library
+#
+CONFIG_RTE_LIBRTE_BOND=y
+
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
diff --git a/lib/Makefile b/lib/Makefile
index b92b392..9995ba8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -47,6 +47,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += librte_pmd_pcap
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
+DIRS-$(CONFIG_RTE_LIBRTE_BOND) += librte_bond
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net
diff --git a/lib/librte_bond/Makefile b/lib/librte_bond/Makefile
new file mode 100644
index 0000000..7514378
--- /dev/null
+++ b/lib/librte_bond/Makefile
@@ -0,0 +1,28 @@
+# <COPYRIGHT_TAG>
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_bond.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_BOND) += rte_bond.c
+
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_bond.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_BOND) += lib/librte_mbuf lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_BOND) += lib/librte_malloc
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_bond/rte_bond.c b/lib/librte_bond/rte_bond.c
new file mode 100644
index 0000000..35dff25
--- /dev/null
+++ b/lib/librte_bond/rte_bond.c
@@ -0,0 +1,1679 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <linux/binfmts.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_memory.h>
+#include <rte_string_fns.h>
+#include <rte_cycles.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_etheraddr.h>
+
+#include "rte_bond.h"
+
+static const char *driver_name = "Link Bonding PMD";
+
+/** Port Queue Mapping Structure */
+struct bond_rx_queue {
+	int queue_id;							/**< Queue Id */
+	struct bond_dev_private *dev_private;	/**< Reference to eth_dev private
+												 structure */
+
+	uint16_t nb_rx_desc;					/**< Number of RX descriptors
+												 available for the queue */
+	struct rte_eth_rxconf rx_conf;			/**< Copy of RX configuration
+												 structure for queue */
+	struct rte_mempool *mb_pool;			/**< Reference to mbuf pool to use
+												 for RX queue */
+};
+
+struct bond_tx_queue {
+	int queue_id;							/**< Queue Id */
+	struct bond_dev_private *dev_private;	/**< Reference to dev private
+												 structure */
+	uint16_t nb_tx_desc;					/**< Number of TX descriptors
+												 available for the queue */
+	struct rte_eth_txconf tx_conf;			/**< 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 */
+};
+
+/** Link Bonding PMD device private configuration Structure */
+struct bond_dev_private {
+	uint8_t mode;						/**< Link Bonding Mode */
+	uint8_t primary_port;				/**< Primary Slave Port */
+	uint8_t balance_xmit_policy;		/**< Transmit policy - l2 / l23 / l34
+											 for operation in balance mode */
+	uint8_t user_defined_mac;			/**< Flag for whether MAC address is
+											 user defined or not */
+	uint8_t promiscuous_en;				/**< Enabled/disable promiscuous mode on
+											slave devices */
+	uint8_t link_props_set;				/**< Bonded eth_dev link properties set*/
+
+	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_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];
+};
+
+static struct slave_conf *
+slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id);
+
+static int
+valid_bonded_ethdev(struct rte_eth_dev *eth_dev)
+{
+	size_t len;
+
+	/* Check valid pointer */
+	if (eth_dev->driver->pci_drv.name == NULL || driver_name == NULL)
+		return -1;
+
+	/* Check string lengths are equal */
+	len = strlen(driver_name);
+	if (strlen(eth_dev->driver->pci_drv.name) != len)
+		return -1;
+
+	/* Compare strings */
+	return strncmp(eth_dev->driver->pci_drv.name, driver_name, len);
+}
+
+static int
+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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+valid_bonded_port_id(uint8_t port_id)
+{
+	/* Verify that port id's are valid */
+	if (valid_port_id(port_id))
+		return -1;
+
+	/* 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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+valid_slave_port_id(uint8_t port_id)
+{
+	/* Verify that port id's are valid */
+	if (valid_port_id(port_id))
+		return -1;
+
+	/* Verify that port_id refers to a non bonded port */
+	if (!valid_bonded_ethdev(&rte_eth_devices[port_id]))
+		return -1;
+
+	return 0;
+}
+
+
+static uint16_t
+bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+
+	uint16_t num_rx_slave = 0;
+	uint16_t num_rx_total = 0;
+
+	int i;
+
+	/* Cast to structure, containing bonded device's port id and queue id */
+	struct bond_rx_queue *bd_rx_q = (struct bond_rx_queue *)queue;
+
+	internals = bd_rx_q->dev_private;
+
+	switch (internals->mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BROADCAST:
+	case BONDING_MODE_BALANCE:
+		for (i = 0; i < internals->active_slave_count; i++) {
+			/* Offset of pointer to *bufs increases as packets are received
+			 * from other slaves */
+			num_rx_slave = rte_eth_rx_burst(internals->active_slaves[i],
+					bd_rx_q->queue_id, bufs + num_rx_total, nb_pkts);
+			if (num_rx_slave)
+				num_rx_total += num_rx_slave;
+		}
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+		num_rx_slave = rte_eth_rx_burst(internals->primary_port,
+				bd_rx_q->queue_id, bufs, nb_pkts);
+		if (num_rx_slave)
+			num_rx_total = num_rx_slave;
+		break;
+	}
+	return num_rx_total;
+}
+
+
+static uint16_t
+bond_ethdev_tx_round_robin(void *queue, struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	struct bond_dev_private *dev_private;
+	struct bond_tx_queue *bd_tx_q;
+
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS][nb_pkts];
+	uint16_t slave_nb_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	static int last_slave_idx = -1;
+	int i, slave_idx;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	dev_private = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = dev_private->active_slave_count;
+	memcpy(slaves, dev_private->active_slaves,
+			sizeof(dev_private->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return num_tx_total;
+
+	/* Populate slaves mbuf with which packets are to be sent on it  */
+	for (i = 0; i < nb_pkts; i++) {
+		slave_idx = i % num_of_slaves;
+		slave_bufs[slave_idx][(slave_nb_pkts[slave_idx])++] = bufs[i];
+	}
+
+	/* calculate the next slave to transmit on based on the last slave idx used
+	 * in the last call to bond_ethdev_tx_burst_round_robin */
+	slave_idx = last_slave_idx + 1;
+
+	/* Send packet burst on each slave device */
+	for (i = 0; i < num_of_slaves; i++) {
+		slave_idx = (slave_idx + i) % num_of_slaves;
+
+		if (slave_nb_pkts[i] > 0) {
+			num_tx_total += rte_eth_tx_burst(slaves[slave_idx],
+					bd_tx_q->queue_id, slave_bufs[i], slave_nb_pkts[i]);
+		}
+	}
+
+	last_slave_idx = slave_idx;
+
+	return num_tx_total;
+}
+
+static uint16_t bond_ethdev_tx_active_backup(void *queue,
+		struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	if (internals->active_slave_count < 1)
+		return 0;
+
+	return rte_eth_tx_burst(internals->primary_port, bd_tx_q->queue_id,
+			bufs, nb_pkts);
+}
+
+
+static inline uint16_t
+ether_hash(struct ether_hdr *eth_hdr)
+{
+	uint16_t *word_src_addr = (uint16_t *)eth_hdr->s_addr.addr_bytes;
+	uint16_t *word_dst_addr = (uint16_t *)eth_hdr->d_addr.addr_bytes;
+
+	return (word_src_addr[0] ^ word_dst_addr[0]) ^
+			(word_src_addr[1] ^ word_dst_addr[1]) ^
+			(word_src_addr[2] ^ word_dst_addr[2]);
+}
+
+static inline uint32_t
+ipv4_hash(struct ipv4_hdr *ipv4_hdr)
+{
+	return (ipv4_hdr->src_addr ^ ipv4_hdr->dst_addr) & 0xFFFF;
+}
+
+static inline uint32_t
+ipv6_hash(struct ipv6_hdr *ipv6_hdr)
+{
+	uint32_t *word_src_addr = (uint32_t *)&(ipv6_hdr->src_addr[0]);
+	uint32_t *word_dst_addr = (uint32_t *)&(ipv6_hdr->dst_addr[0]);
+
+	return (word_src_addr[0] ^ word_dst_addr[0]) ^
+			(word_src_addr[1] ^ word_dst_addr[1]) ^
+			(word_src_addr[2] ^ word_dst_addr[2]) ^
+			(word_src_addr[3] ^ word_dst_addr[3]);
+}
+
+static uint32_t
+udp_hash(struct udp_hdr *hdr) {
+	return hdr->src_port ^ hdr->dst_port;
+}
+
+static inline uint16_t
+xmit_slave_hash(const struct rte_mbuf *buf, uint8_t slave_count, uint8_t policy)
+{
+	struct ether_hdr *eth_hdr;
+	struct udp_hdr *udp_hdr;
+	size_t eth_offset = 0;
+	uint32_t hash = 0;
+
+	if (slave_count == 1)
+		return 0;
+
+	switch (policy) {
+	case BALANCE_XMIT_POLICY_LAYER2:
+		eth_hdr = (struct ether_hdr *)buf->pkt.data;
+
+		hash = ether_hash(eth_hdr);
+		hash ^= hash >> 8;
+		return hash % slave_count;
+
+
+	case BALANCE_XMIT_POLICY_LAYER23:
+		eth_hdr = (struct ether_hdr *)buf->pkt.data;
+
+		if (buf->ol_flags & PKT_RX_VLAN_PKT)
+			eth_offset = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_offset = sizeof(struct ether_hdr);
+
+		if (buf->ol_flags & PKT_RX_IPV4_HDR) {
+			struct ipv4_hdr *ipv4_hdr;
+			ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(buf,
+					unsigned char *) + eth_offset);
+
+			hash = ether_hash(eth_hdr) ^ ipv4_hash(ipv4_hdr);
+
+		} else {
+			struct ipv6_hdr *ipv6_hdr;
+
+			ipv6_hdr = (struct ipv6_hdr *)(rte_pktmbuf_mtod(buf,
+					unsigned char *) + eth_offset);
+
+			hash = ether_hash(eth_hdr) ^ ipv6_hash(ipv6_hdr);
+		}
+		break;
+
+	case BALANCE_XMIT_POLICY_LAYER34:
+		if (buf->ol_flags & PKT_RX_VLAN_PKT)
+			eth_offset = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_offset = sizeof(struct ether_hdr);
+
+		if (buf->ol_flags & PKT_RX_IPV4_HDR) {
+			struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)
+					(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset);
+
+			if (ipv4_hdr->next_proto_id == IPPROTO_UDP) {
+				udp_hdr = (struct udp_hdr *)
+						(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset +
+								sizeof(struct ipv4_hdr));
+				hash = ipv4_hash(ipv4_hdr) ^ udp_hash(udp_hdr);
+			} else {
+				hash = ipv4_hash(ipv4_hdr);
+			}
+		} else {
+			struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)
+					(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset);
+
+			if (ipv6_hdr->proto == IPPROTO_UDP) {
+				udp_hdr = (struct udp_hdr *)
+						(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset +
+								sizeof(struct ipv6_hdr));
+				hash = ipv6_hash(ipv6_hdr) ^ udp_hash(udp_hdr);
+			} else {
+				hash = ipv6_hash(ipv6_hdr);
+			}
+		}
+		break;
+	}
+
+	hash ^= hash >> 16;
+	hash ^= hash >> 8;
+
+	return hash % slave_count;
+}
+
+static uint16_t
+bond_ethdev_tx_balance(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	int i, op_slave_id;
+
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS][nb_pkts];
+	uint16_t slave_nb_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = internals->active_slave_count;
+	memcpy(slaves, internals->active_slaves,
+			sizeof(internals->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return num_tx_total;
+
+	/* Populate slaves mbuf with the packets which are to be sent on it  */
+	for (i = 0; i < nb_pkts; i++) {
+		/* Select output slave using hash based on xmit policy */
+		op_slave_id = xmit_slave_hash(bufs[i], num_of_slaves,
+									  internals->balance_xmit_policy);
+		slave_bufs[op_slave_id][slave_nb_pkts[op_slave_id]++] = bufs[i];
+	}
+
+	/* Send packet burst on each slave device */
+	for (i = 0; i < num_of_slaves; i++) {
+		if (slave_nb_pkts[i] > 0) {
+			num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
+					slave_bufs[i], slave_nb_pkts[i]);
+		}
+	}
+
+	return num_tx_total;
+}
+
+static uint16_t
+bond_ethdev_tx_broadcast(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	int i;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = internals->active_slave_count;
+	memcpy(slaves, internals->active_slaves,
+			sizeof(internals->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return 0;
+
+
+	for (i = 0; i < num_of_slaves; i++) {
+		num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
+				bufs, nb_pkts);
+	}
+
+	return num_tx_total;
+}
+
+static void
+link_properties_set(struct rte_eth_dev *bonded_eth_dev,
+		struct rte_eth_link *slave_dev_link)
+{
+	struct rte_eth_link *bonded_dev_link = &bonded_eth_dev->data->dev_link;
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	if (slave_dev_link->link_status &&
+		bonded_eth_dev->data->dev_started) {
+		bonded_dev_link->link_duplex = slave_dev_link->link_duplex;
+		bonded_dev_link->link_speed = slave_dev_link->link_speed;
+
+		internals->link_props_set = 1;
+	}
+}
+
+static void
+link_properties_reset(struct rte_eth_dev *bonded_eth_dev)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	memset(&(bonded_eth_dev->data->dev_link), 0,
+			sizeof(bonded_eth_dev->data->dev_link));
+
+	internals->link_props_set = 0;
+}
+
+static int
+link_properties_valid(struct rte_eth_link *bonded_dev_link,
+		struct rte_eth_link *slave_dev_link)
+{
+	if (bonded_dev_link->link_duplex != slave_dev_link->link_duplex ||
+		bonded_dev_link->link_speed !=  slave_dev_link->link_speed)
+		return -1;
+
+	return 0;
+}
+
+static int
+mac_address_set(struct rte_eth_dev *eth_dev, struct ether_addr *new_mac_addr)
+{
+	struct ether_addr *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__);
+		return -1;
+	}
+
+	if (new_mac_addr == NULL) {
+		RTE_LOG(ERR, PMD, "%s: NULL pointer MAC specified\n", __func__);
+		return -1;
+	}
+
+	/* if new MAC is different to current MAC then update */
+	if (memcmp(mac_addr, new_mac_addr, sizeof(*mac_addr)))
+		memcpy(mac_addr, new_mac_addr, sizeof(*mac_addr));
+
+	return 0;
+}
+
+static int
+mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
+{
+	struct bond_dev_private *internals;
+	int i;
+
+	internals = bonded_eth_dev->data->dev_private;
+
+	/* Update slave devices MAC addresses */
+	if (internals->slave_count < 1)
+		return -1;
+
+	switch (internals->mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+	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]],
+					bonded_eth_dev->data->mac_addrs)) {
+				RTE_LOG(ERR, PMD,
+						"%s: Failed to update port Id %d MAC address\n",
+						__func__, internals->slaves[i]);
+				return -1;
+			}
+		}
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		for (i = 0; i < internals->slave_count; i++) {
+			if (internals->slaves[i] == internals->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->primary_port);
+				}
+			} 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]);
+
+
+					return -1;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+static int
+bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
+{
+	struct bond_dev_private *internals;
+
+	internals = eth_dev->data->dev_private;
+
+	switch (mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_round_robin;
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_active_backup;
+		break;
+	case BONDING_MODE_BALANCE:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_balance;
+		break;
+	case BONDING_MODE_BROADCAST:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_broadcast;
+		break;
+	default:
+		return -1;
+	}
+	internals->mode = mode;
+
+	return 0;
+}
+
+static int
+slave_configure(struct rte_eth_dev *bonded_eth_dev,
+		struct rte_eth_dev *slave_eth_dev)
+{
+	struct slave_conf *presisted_slave_conf;
+	struct bond_dev_private *internals;
+
+	struct bond_rx_queue *bd_rx_q;
+	struct bond_tx_queue *bd_tx_q;
+
+	int q_id;
+
+	internals = bonded_eth_dev->data->dev_private;
+
+	presisted_slave_conf = slave_config_get(internals,
+											slave_eth_dev->data->port_id);
+
+	if (presisted_slave_conf == NULL)
+		return -1;
+
+	/* 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;
+
+	if (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;
+	}
+
+	/* 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,
+				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;
+		}
+	}
+
+	/* Setup Tx Queues */
+	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,
+				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;
+		}
+	}
+
+	/* 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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static 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;
+}
+
+static void
+slave_config_clear(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) {
+			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]));
+		}
+	}
+}
+
+static void
+slave_config_store(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];
+
+	presisted_slave_conf->port_id = slave_eth_dev->data->port_id;
+
+	memcpy(&(presisted_slave_conf->mac_addr),
+		   slave_eth_dev->data->mac_addrs,
+		   sizeof(struct ether_addr));
+}
+
+static void
+bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev);
+
+static int
+bond_ethdev_start(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals;
+	int i;
+
+	/* 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);
+		return -1;
+	}
+
+	eth_dev->data->dev_link.link_status = 1;
+	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__);
+		return -1;
+	}
+
+	if (!internals->user_defined_mac) {
+		struct slave_conf *conf = slave_config_get(internals,
+				internals->primary_port);
+
+		if (mac_address_set(eth_dev, &conf->mac_addr) != 0)
+			return -1;
+	}
+
+	/* Update all slave devices MACs*/
+	if (mac_address_slaves_update(eth_dev) != 0)
+		return -1;
+
+	/* If bonded device is configure in promiscuous mode then re-apply config */
+	if (internals->promiscuous_en)
+		bond_ethdev_promiscuous_enable(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)",
+					eth_dev->data->port_id, internals->slaves[i]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static void
+bond_ethdev_stop(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals = eth_dev->data->dev_private;
+
+	internals->active_slave_count = 0;
+
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_started = 0;
+}
+
+static void
+bond_ethdev_close(struct rte_eth_dev *dev __rte_unused)
+{
+}
+
+static int
+bond_ethdev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static void
+bond_ethdev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
+{
+	dev_info->driver_name = driver_name;
+	dev_info->max_mac_addrs = 1;
+
+	dev_info->max_rx_pktlen = (uint32_t)2048;
+
+	dev_info->max_rx_queues = (uint16_t)128;
+	dev_info->max_tx_queues = (uint16_t)512;
+
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = dev->pci_dev;
+}
+
+static int
+bond_ethdev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc, unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool)
+{
+	struct bond_rx_queue *bd_rx_q;
+
+	bd_rx_q = (struct bond_rx_queue *)rte_zmalloc_socket(NULL,
+			sizeof(struct bond_rx_queue), 0, dev->pci_dev->numa_node);
+	if (bd_rx_q == NULL)
+		return -1;
+
+	bd_rx_q->queue_id = rx_queue_id;
+	bd_rx_q->dev_private = dev->data->dev_private;
+
+	bd_rx_q->nb_rx_desc = nb_rx_desc;
+
+	memcpy(&(bd_rx_q->rx_conf), rx_conf, sizeof(struct rte_eth_rxconf));
+	bd_rx_q->mb_pool = mb_pool;
+
+	dev->data->rx_queues[rx_queue_id] = bd_rx_q;
+
+	return 0;
+}
+
+static int
+bond_ethdev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc, unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf)
+{
+	struct bond_tx_queue *bd_tx_q;
+
+	bd_tx_q = (struct bond_tx_queue *)rte_zmalloc_socket(NULL,
+			sizeof(struct bond_tx_queue), 0, dev->pci_dev->numa_node);
+
+	bd_tx_q->queue_id = tx_queue_id;
+	bd_tx_q->dev_private = dev->data->dev_private;
+
+	bd_tx_q->nb_tx_desc = nb_tx_desc;
+	memcpy(&(bd_tx_q->tx_conf), tx_conf, sizeof(bd_tx_q->tx_conf));
+
+	dev->data->tx_queues[tx_queue_id] = bd_tx_q;
+
+	return 0;
+}
+
+static void
+bond_ethdev_rx_queue_release(void *queue)
+{
+	if (queue == NULL)
+		return;
+
+	rte_free(queue);
+}
+
+static void
+bond_ethdev_tx_queue_release(void *queue)
+{
+	if (queue == NULL)
+		return;
+
+	rte_free(queue);
+}
+
+
+static int
+bond_ethdev_link_update(struct rte_eth_dev *bonded_eth_dev,
+		int wait_to_complete)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	if (!bonded_eth_dev->data->dev_started ||
+		internals->active_slave_count == 0) {
+		bonded_eth_dev->data->dev_link.link_status = 0;
+		return 0;
+	} else {
+		struct rte_eth_dev *slave_eth_dev;
+		int i, link_up = 0;
+
+		for (i = 0; i < internals->active_slave_count; i++) {
+			slave_eth_dev = &rte_eth_devices[internals->active_slaves[i]];
+
+			(*slave_eth_dev->dev_ops->link_update)(slave_eth_dev,
+					wait_to_complete);
+			if (slave_eth_dev->data->dev_link.link_status == 1) {
+				link_up = 1;
+				break;
+			}
+		}
+
+		bonded_eth_dev->data->dev_link.link_status = link_up;
+	}
+
+	return 0;
+}
+
+static void
+bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	struct rte_eth_stats slave_stats;
+
+	int i;
+
+	/* clear bonded stats before populating from slaves */
+	memset(stats, 0, sizeof(*stats));
+
+	for (i = 0; i < internals->slave_count; i++) {
+		rte_eth_stats_get(internals->slaves[i], &slave_stats);
+
+		stats->ipackets += slave_stats.ipackets;
+		stats->opackets += slave_stats.opackets;
+		stats->ibytes += slave_stats.ibytes;
+		stats->obytes += slave_stats.obytes;
+		stats->ierrors += slave_stats.ierrors;
+		stats->oerrors += slave_stats.oerrors;
+		stats->imcasts += slave_stats.imcasts;
+		stats->rx_nombuf += slave_stats.rx_nombuf;
+		stats->fdirmatch += slave_stats.fdirmatch;
+		stats->fdirmiss += slave_stats.fdirmiss;
+		stats->tx_pause_xon += slave_stats.tx_pause_xon;
+		stats->rx_pause_xon += slave_stats.rx_pause_xon;
+		stats->tx_pause_xoff += slave_stats.tx_pause_xoff;
+		stats->rx_pause_xoff += slave_stats.rx_pause_xoff;
+	}
+}
+
+static void
+bond_ethdev_stats_reset(struct rte_eth_dev *dev)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < internals->slave_count; i++)
+		rte_eth_stats_reset(internals->slaves[i]);
+}
+
+static void
+bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals = eth_dev->data->dev_private;
+	int i;
+
+	internals->promiscuous_en = 1;
+
+	switch (internals->mode) {
+	/* Promiscuous mode is propagated to all slaves */
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BALANCE:
+	case BONDING_MODE_BROADCAST:
+		for (i = 0; i < internals->slave_count; i++)
+			rte_eth_promiscuous_enable(internals->slaves[i]);
+		break;
+	/* Promiscuous mode is propagated only to primary slave */
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		rte_eth_promiscuous_enable(internals->primary_port);
+
+	}
+}
+
+static void
+bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	int i;
+
+	internals->promiscuous_en = 0;
+
+	switch (internals->mode) {
+	/* Promiscuous mode is propagated to all slaves */
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BALANCE:
+	case BONDING_MODE_BROADCAST:
+		for (i = 0; i < internals->slave_count; i++)
+			rte_eth_promiscuous_disable(internals->slaves[i]);
+		break;
+	/* Promiscuous mode is propagated only to primary slave */
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		rte_eth_promiscuous_disable(internals->primary_port);
+	}
+}
+
+
+static void
+bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,
+		void *param)
+{
+	struct rte_eth_dev *bonded_eth_dev, *slave_eth_dev;
+	struct bond_dev_private *internals;
+	struct rte_eth_link link;
+
+	int i, bonded_port_id, valid_slave, active_pos = -1;
+
+	if (type != RTE_ETH_EVENT_INTR_LSC)
+		return;
+
+	if (param == NULL)
+		return;
+
+	bonded_port_id = *(uint8_t *)param;
+
+	bonded_eth_dev = &rte_eth_devices[bonded_port_id];
+	slave_eth_dev = &rte_eth_devices[port_id];
+
+	if (valid_bonded_ethdev(bonded_eth_dev))
+		return;
+
+	internals = bonded_eth_dev->data->dev_private;
+
+	/* If the device isn't started don't handle interrupts */
+	if (!bonded_eth_dev->data->dev_started)
+		return;
+
+	/* 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) {
+			valid_slave = 1;
+			break;
+		}
+	}
+
+	if (!valid_slave)
+		return;
+
+	/* Search for port in active port list */
+	for (i = 0; i < internals->active_slave_count; i++) {
+		if (port_id == internals->active_slaves[i]) {
+			active_pos = i;
+			break;
+		}
+	}
+
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status) {
+		if (active_pos == -1) {
+			/* if no active slave ports then set this port to be primary port */
+			if (internals->active_slave_count == 0) {
+				/* If first active slave, then change link status */
+				bonded_eth_dev->data->dev_link.link_status = 1;
+				internals->primary_port = port_id;
+
+				/* Inherit eth dev link properties from first active slave */
+				link_properties_set(bonded_eth_dev,
+						&(slave_eth_dev->data->dev_link));
+
+			}
+			internals->active_slaves[internals->active_slave_count++] = port_id;
+		}
+	} else {
+		if (active_pos != -1) {
+			/* Remove from active slave list */
+			for (i = active_pos; i < (internals->active_slave_count - 1); i++)
+				internals->active_slaves[i] = internals->active_slaves[i+1];
+
+			internals->active_slave_count--;
+
+			/* No active slaves, change link status to down and reset other
+			 * link properties */
+			if (internals->active_slave_count == 0)
+				link_properties_reset(bonded_eth_dev);
+
+			/* Update primary id, take first active slave from list or if none
+			 * available set to -1 */
+			if (port_id == internals->primary_port) {
+				if (internals->active_slave_count > 0)
+					internals->primary_port = internals->active_slaves[0];
+				else
+					internals->primary_port = internals->slaves[0];
+			}
+		}
+	}
+}
+
+static struct eth_dev_ops default_dev_ops = {
+		.dev_start = bond_ethdev_start,
+		.dev_stop = bond_ethdev_stop,
+		.dev_close = bond_ethdev_close,
+		.dev_configure = bond_ethdev_configure,
+		.dev_infos_get = bond_ethdev_info,
+		.rx_queue_setup = bond_ethdev_rx_queue_setup,
+		.tx_queue_setup = bond_ethdev_tx_queue_setup,
+		.rx_queue_release = bond_ethdev_rx_queue_release,
+		.tx_queue_release = bond_ethdev_tx_queue_release,
+		.link_update = bond_ethdev_link_update,
+		.stats_get = bond_ethdev_stats_get,
+		.stats_reset = bond_ethdev_stats_reset,
+		.promiscuous_enable = bond_ethdev_promiscuous_enable,
+		.promiscuous_disable = bond_ethdev_promiscuous_disable
+};
+
+static uint8_t
+number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; ((i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL)); i++) {
+		if (sockets < ms[i].socket_id)
+			sockets = ms[i].socket_id;
+	}
+
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+
+}
+
+int
+rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
+{
+	struct rte_pci_device *pci_dev = NULL;
+	struct bond_dev_private *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct eth_driver *eth_drv = NULL;
+	struct rte_pci_driver *pci_drv = NULL;
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+
+	if (name == NULL) {
+		RTE_LOG(ERR, PMD, "Invalid name specified\n");
+		goto err;
+	}
+
+	if (socket_id >= number_of_sockets()) {
+		RTE_LOG(ERR, PMD,
+				"%s: invalid socket id specified to create bonded device on.\n",
+				__func__);
+		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");
+		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");
+		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");
+		goto err;
+	}
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, socket_id);
+	if (internals == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to malloc internals on socket");
+		goto err;
+	}
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate();
+	if (eth_dev == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to allocate rte_eth_dev");
+		goto err;
+	}
+
+	pci_dev->numa_node = socket_id;
+	pci_drv->name = driver_name;
+
+	eth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);
+	eth_dev->driver = eth_drv;
+
+	eth_dev->data->dev_private = internals;
+	eth_dev->data->nb_rx_queues = (uint16_t)1;
+	eth_dev->data->nb_tx_queues = (uint16_t)1;
+
+	eth_dev->data->dev_link.link_status = 0;
+
+	eth_dev->data->mac_addrs = rte_zmalloc(name, ETHER_ADDR_LEN, 0);
+
+	eth_dev->data->dev_started = 0;
+	eth_dev->data->promiscuous = 0;
+	eth_dev->data->scattered_rx = 0;
+	eth_dev->data->all_multicast = 0;
+
+	eth_dev->dev_ops = &default_dev_ops;
+	eth_dev->pci_dev = pci_dev;
+
+	eth_dev->rx_pkt_burst = bond_ethdev_rx_burst;
+	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);
+		goto err;
+	}
+
+	internals->primary_port = 0;
+	internals->balance_xmit_policy = BALANCE_XMIT_POLICY_LAYER2;
+	internals->user_defined_mac = 0;
+	internals->link_props_set = 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:
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (pci_drv)
+		rte_free(pci_drv);
+	if (eth_drv)
+		rte_free(eth_drv);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+
+
+int
+rte_eth_bond_slave_add(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;
+	struct bond_dev_private *temp_internals;
+	struct rte_eth_link link_props;
+
+	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;
+
+	/*
+	 * 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;
+			}
+		}
+	}
+
+	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);
+
+	if (internals->slave_count == 0) {
+		/* 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));
+
+		/* Make primary slave */
+		rte_eth_bond_primary_set(bonded_port_id, slave_port_id);
+	} else {
+		/* Check slave link properties are supported if props are set,
+		 * all slaves must be the same */
+		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;
+			}
+		} else {
+			link_properties_set(bonded_eth_dev,
+					&(slave_eth_dev->data->dev_link));
+		}
+	}
+
+	internals->slave_count++;
+
+	/* Update all slave devices MACs*/
+	mac_address_slaves_update(bonded_eth_dev);
+
+	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",
+					slave_port_id);
+			goto err_add;
+		}
+	}
+
+	/* Register link status change callback with bonded device pointer as
+	 * argument*/
+	rte_eth_dev_callback_register(slave_port_id, RTE_ETH_EVENT_INTR_LSC,
+			bond_ethdev_lsc_event_callback, &bonded_eth_dev->data->port_id);
+
+	/* If bonded device is started then we can add the slave to our active
+	 * slave array */
+	if (bonded_eth_dev->data->dev_started) {
+		rte_eth_link_get_nowait(slave_port_id, &link_props);
+
+		 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)
+{
+	struct bond_dev_private *internals;
+	struct slave_conf *slave_conf;
+
+	int i;
+	int pos = -1;
+
+	/* Verify that port id's are valid bonded and slave ports */
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		goto err_del;
+
+	if (valid_slave_port_id(slave_port_id) != 0)
+		goto err_del;
+
+	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;
+
+		/* shift active slaves up active array list */
+		if (pos >= 0 && i < (internals->active_slave_count - 1))
+			internals->active_slaves[i] = internals->active_slaves[i+1];
+	}
+
+	if (pos >= 0)
+		internals->active_slave_count--;
+
+	/* UnRegister link status change callback with bonded device pointer as
+	 * argument*/
+	rte_eth_dev_callback_unregister(slave_port_id, RTE_ETH_EVENT_INTR_LSC,
+			bond_ethdev_lsc_event_callback,
+			&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));
+
+
+	pos = -1;
+	/* now remove from slave list */
+	for (i = 0; i < internals->slave_count; i++) {
+		if (internals->slaves[i] == slave_port_id)
+			pos = i;
+
+		/* shift slaves up list */
+		if (pos >= 0 && i < (internals->slave_count - 1))
+			internals->slaves[i] = internals->slaves[i+1];
+	}
+
+	slave_config_clear(internals, &rte_eth_devices[slave_port_id]);
+
+	if (pos < 0)
+		goto err_del;
+
+	internals->slave_count--;
+
+	/*  first slave in the active list will be the primary by default,
+	 *  otherwise use first device in list */
+	if (internals->primary_port == slave_port_id &&
+			internals->active_slave_count > 0)
+		internals->primary_port = internals->active_slaves[0];
+
+	if (internals->active_slave_count < 1) {
+		/* reset device link properties as no slaves are active */
+		link_properties_reset(&rte_eth_devices[bonded_port_id]);
+
+		/* if no slaves are any longer attached to bonded device and MAC is not
+		 * user defined then clear MAC of bonded device  as it will be reset
+		 * when a new slave is added */
+		if (internals->slave_count < 1 && !internals->user_defined_mac)
+			memset(rte_eth_devices[bonded_port_id].data->mac_addrs, 0,
+					sizeof(*(rte_eth_devices[bonded_port_id].data->mac_addrs)));
+	}
+
+	return 0;
+
+err_del:
+	RTE_LOG(ERR, PMD,
+			"Cannot remove slave device (not present in bonded device)\n");
+	return -1;
+
+}
+
+int
+rte_eth_bond_mode_set(uint8_t bonded_port_id, uint8_t mode)
+{
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	return bond_ethdev_mode_set(&rte_eth_devices[bonded_port_id], mode);
+}
+
+
+int
+rte_eth_bond_mode_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->mode;
+}
+
+int
+rte_eth_bond_primary_set(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+	struct bond_dev_private *internals;
+	int i;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (valid_slave_port_id(slave_port_id) != 0)
+		return -1;
+
+	internals =  rte_eth_devices[bonded_port_id].data->dev_private;
+
+	/* Search bonded device slave ports for new proposed primary port */
+	for (i = 0; i < internals->slave_count; i++) {
+		if (internals->slaves[i] == slave_port_id) {
+			/* Found slave device in active slave list */
+			internals->primary_port = slave_port_id;
+			return 0;
+		}
+	}
+
+	/* Slave is not bound to this master device */
+	return -1;
+}
+
+int
+rte_eth_bond_primary_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;
+
+	if (internals->slave_count < 1)
+		return -1;
+
+	return internals->primary_port;
+}
+
+int
+rte_eth_bond_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves)
+{
+	struct bond_dev_private *internals;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (slaves == NULL)
+		return -1;
+
+	internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+	*slaves = (uint8_t *)(&internals->slaves);
+
+	return internals->slave_count;
+
+}
+
+int
+rte_eth_bond_active_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves)
+{
+	struct bond_dev_private *internals;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (slaves == NULL)
+		return -1;
+
+	internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+	*slaves = (uint8_t *)(&internals->active_slaves);
+
+	return internals->active_slave_count;
+
+}
+
+
+int
+rte_eth_bond_mac_address_set(uint8_t bonded_port_id,
+		struct ether_addr *mac_addr)
+{
+	struct rte_eth_dev *bonded_eth_dev;
+	struct bond_dev_private *internals;
+
+	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;
+
+	/* Set MAC Address of Bonded Device */
+	if (mac_address_set(bonded_eth_dev, mac_addr))
+		return -1;
+
+	internals->user_defined_mac = 1;
+
+	/* Update all slave devices MACs*/
+	if (internals->slave_count > 0)
+		return mac_address_slaves_update(bonded_eth_dev);
+
+	return 0;
+}
+
+
+int
+rte_eth_bond_mac_address_reset(uint8_t bonded_port_id)
+{
+	struct rte_eth_dev *bonded_eth_dev;
+	struct bond_dev_private *internals;
+
+
+	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;
+
+	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)
+			return -1;
+
+		/* Update all slave devices MAC addresses */
+		return mac_address_slaves_update(bonded_eth_dev);
+	}
+	/* No need to update anything as no slaves present */
+	return 0;
+}
+
+int
+rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy)
+{
+	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;
+
+	switch (policy) {
+	case BALANCE_XMIT_POLICY_LAYER2:
+	case BALANCE_XMIT_POLICY_LAYER23:
+	case BALANCE_XMIT_POLICY_LAYER34:
+		internals->balance_xmit_policy = policy;
+		break;
+
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+
+int
+rte_eth_bond_xmit_policy_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->balance_xmit_policy;
+}
diff --git a/lib/librte_bond/rte_bond.h b/lib/librte_bond/rte_bond.h
new file mode 100644
index 0000000..97b6d5e
--- /dev/null
+++ b/lib/librte_bond/rte_bond.h
@@ -0,0 +1,228 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_BOND_H_
+#define _RTE_ETH_BOND_H_
+
+/**
+ * @file
+ * RTE Link Bonding Ethernet Device
+ * Link Bonding for 1GbE and 10GbE ports to allow the aggregation of multiple
+ * (slave) NICs into a single logical interface. The bonded device processes
+ * these interfaces based on the mode of operation specified and supported.
+ * This implementation supports 4 modes of operation round robin, active backup
+ * balance and broadcast. Providing redundant links, fault tolerance and/or
+ * load balancing of network ports
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ether.h>
+
+/** Link Bonding Mode Definitions */
+#define BONDING_MODE_ROUND_ROBIN		(0)
+#define BONDING_MODE_ACTIVE_BACKUP		(1)
+#define BONDING_MODE_BALANCE			(2)
+#define BONDING_MODE_BROADCAST			(3)
+
+/** Balance Mode Transmit Policy Types */
+#define BALANCE_XMIT_POLICY_LAYER2		(0)
+#define BALANCE_XMIT_POLICY_LAYER23		(1)
+#define BALANCE_XMIT_POLICY_LAYER34		(2)
+
+/**
+ * Create a bonded rte_eth_dev device
+ *
+ * @param name
+ * @param mode
+ * @param socket_id
+ *
+ * @return
+ *	Port Id of created rte_eth_dev on success, negative value otherwise
+ */
+int
+rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id);
+
+/**
+ * Add a rte_eth_dev device as a slave to the bonded device
+ *
+ * @param bonded_port_id
+ * @param slave_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Remove a slave rte_eth_dev device from the bonded device
+ *
+ * @param bonded_port_id
+ * @param slave_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Set link bonding mode of bonded device
+ *
+ * @param bonded_port_id
+ * @param mode
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mode_set(uint8_t bonded_port_id, uint8_t mode);
+
+/**
+ * Get link bonding mode of bonded device
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	link bonding mode on success, negative value otherwise
+ */
+int
+rte_eth_bond_mode_get(uint8_t bonded_port_id);
+
+/**
+ * Set slave rte_eth_dev as primary slave of bonded device
+ *
+ * @param bonded_port_id
+ * @param slave_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_primary_set(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Get primary slave of bonded device
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	Port Id of primary slave on success, -1 on failure
+ */
+int
+rte_eth_bond_primary_get(uint8_t bonded_port_id);
+
+/**
+ * Populate an array with list of the slaves port id's of the bonded device
+ *
+ * @param bonded_port_id
+ * @param slaves
+ *
+ * @return
+ *	number of slaves associated with bonded device on success,
+ *	negative value otherwise
+ */
+int
+rte_eth_bond_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves);
+
+/**
+ * Populate an array with list of the active slaves port id's of the bonded
+ * device.
+ *
+ * @param bonded_port_id
+ * @param slaves
+ *
+ * @return
+ *	number of active slaves associated with bonded device on success,
+ *	negative value otherwise
+ */
+int
+rte_eth_bond_active_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves);
+
+/**
+ * Set explicit MAC address to use on bonded device and it's slaves.
+ *
+ * @param bonded_port_id
+ * @param mac_addr
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mac_address_set(uint8_t bonded_port_id,
+		struct ether_addr *mac_addr);
+
+/**
+ * Reset bonded device to use MAC from primary slave on bonded device and it's
+ * slaves.
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mac_address_reset(uint8_t bonded_port_id);
+
+/**
+ * Set the transmit policy for bonded device to use when it is operating in
+ * balance mode
+ *
+ * @param bonded_port_id
+ * @param policy
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy);
+
+/**
+ * Get the transmit policy set on bonded device for balance mode operation
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	balance transmit policy on success, negative value otherwise
+ */
+int
+rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index a836577..a803a5c 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -177,8 +177,13 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_PCAP),y)
 LDLIBS += -lrte_pmd_pcap -lpcap
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_BOND),y)
+LDLIBS += -lrte_bond
 endif
 
+endif
+
+
 LDLIBS += $(EXECENV_LDLIBS)
 
 LDLIBS += --end-group
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH 2/4] Link bonding unit tests
  2014-05-28 15:32 [dpdk-dev] [PATCH 0/4] Link Bonding Library declan.doherty
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 1/4] " declan.doherty
@ 2014-05-28 15:32 ` declan.doherty
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 3/4] Link bonding integration into testpmd declan.doherty
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 127+ messages in thread
From: declan.doherty @ 2014-05-28 15:32 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

Link bonding unit tests, including code to generate packet bursts 
for testing rx and tx functionality of bonded device and a
 virtual/stubbed out ethdev for use as slave ethdev in testing


Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 app/test/Makefile                 |    3 +
 app/test/commands.c               |    3 +
 app/test/packet_burst_generator.c |  276 +++
 app/test/packet_burst_generator.h |   85 +
 app/test/test.h                   |    1 +
 app/test/test_link_bonding.c      | 4007 +++++++++++++++++++++++++++++++++++++
 app/test/virtual_pmd.c            |  580 ++++++
 app/test/virtual_pmd.h            |   74 +
 8 files changed, 5029 insertions(+)
 create mode 100644 app/test/packet_burst_generator.c
 create mode 100644 app/test/packet_burst_generator.h
 create mode 100644 app/test/test_link_bonding.c
 create mode 100644 app/test/virtual_pmd.c
 create mode 100644 app/test/virtual_pmd.h

diff --git a/app/test/Makefile b/app/test/Makefile
index b49785e..ac55a11 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_ring_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_rwlock.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_timer.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_mempool.c
+SRCS-$(CONFIG_RTE_APP_TEST) += test_link_bonding.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_mempool_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_mbuf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_logs.c
@@ -94,6 +95,8 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_common.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_timer_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_ivshmem.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_devargs.c
+SRCS-$(CONFIG_RTE_APP_TEST) += virtual_pmd.c
+SRCS-$(CONFIG_RTE_APP_TEST) += packet_burst_generator.c
 
 ifeq ($(CONFIG_RTE_APP_TEST),y)
 SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
diff --git a/app/test/commands.c b/app/test/commands.c
index efa8566..4d0ec3b 100644
--- a/app/test/commands.c
+++ b/app/test/commands.c
@@ -157,6 +157,8 @@ static void cmd_autotest_parsed(void *parsed_result,
 		ret = test_timer();
 	if (!strcmp(res->autotest, "timer_perf_autotest"))
 		ret = test_timer_perf();
+	if (!strcmp(res->autotest, "link_bonding_autotest"))
+		ret = test_link_bonding();
 	if (!strcmp(res->autotest, "mempool_autotest"))
 		ret = test_mempool();
 	if (!strcmp(res->autotest, "mempool_perf_autotest"))
@@ -221,6 +223,7 @@ cmdline_parse_token_string_t cmd_autotest_autotest =
 			"alarm_autotest#interrupt_autotest#"
 			"version_autotest#eal_fs_autotest#"
 			"cmdline_autotest#func_reentrancy_autotest#"
+			"link_bonding_autotest#"
 			"mempool_perf_autotest#hash_perf_autotest#"
 			"memcpy_perf_autotest#ring_perf_autotest#"
 			"red_autotest#meter_autotest#sched_autotest#"
diff --git a/app/test/packet_burst_generator.c b/app/test/packet_burst_generator.c
new file mode 100644
index 0000000..8838068
--- /dev/null
+++ b/app/test/packet_burst_generator.c
@@ -0,0 +1,276 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_byteorder.h>
+#include <rte_mbuf.h>
+
+#include "packet_burst_generator.h"
+
+#define UDP_SRC_PORT 1024
+#define UDP_DST_PORT 1024
+
+
+#define IP_DEFTTL  64   /* from RFC 1340. */
+#define IP_VERSION 0x40
+#define IP_HDRLEN  0x05 /* default IP header length == five 32-bits words. */
+#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
+
+static void copy_buf_to_pkt_segs(void* buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
+{
+	struct rte_mbuf *seg;
+	void *seg_buf;
+	unsigned copy_len;
+
+	seg = pkt;
+	while (offset >= seg->pkt.data_len) {
+		offset -= seg->pkt.data_len;
+		seg = seg->pkt.next;
+	}
+	copy_len = seg->pkt.data_len - offset;
+	seg_buf = ((char *) seg->pkt.data + offset);
+	while (len > copy_len) {
+		rte_memcpy(seg_buf, buf, (size_t) copy_len);
+		len -= copy_len;
+		buf = ((char*) buf + copy_len);
+		seg = seg->pkt.next;
+		seg_buf = seg->pkt.data;
+	}
+	rte_memcpy(seg_buf, buf, (size_t) len);
+}
+
+static inline void
+copy_buf_to_pkt(void* buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
+{
+	if (offset + len <= pkt->pkt.data_len) {
+		rte_memcpy(((char *) pkt->pkt.data + offset), buf, (size_t) len);
+		return;
+	}
+	copy_buf_to_pkt_segs(buf, len, pkt, offset);
+}
+
+
+void initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac, struct ether_addr *dst_mac, uint8_t vlan_enabled, uint16_t van_id)
+{
+	ether_addr_copy(dst_mac, &eth_hdr->d_addr);
+	ether_addr_copy(src_mac, &eth_hdr->s_addr);
+
+	if (vlan_enabled) {
+		struct vlan_hdr * vhdr = (struct vlan_hdr *)((uint8_t*)eth_hdr + sizeof(struct ether_hdr));
+
+		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+
+		vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		vhdr->vlan_tci = van_id;
+	} else {
+		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	}
+
+}
+
+uint16_t initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port, uint16_t dst_port, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct udp_hdr));
+
+	udp_hdr->src_port = rte_cpu_to_be_16(src_port);
+	udp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
+	udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len);
+	udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
+
+	return pkt_len;
+}
+
+
+uint16_t initialize_ipv6_header(struct ipv6_hdr *ip_hdr, uint8_t *src_addr, uint8_t *dst_addr, uint16_t pkt_data_len)
+{
+	ip_hdr->vtc_flow = 0;
+	ip_hdr->payload_len = pkt_data_len;
+	ip_hdr->proto = IPPROTO_UDP;
+	ip_hdr->hop_limits = IP_DEFTTL;
+
+	rte_memcpy(ip_hdr->src_addr, src_addr, sizeof(ip_hdr->src_addr));
+	rte_memcpy(ip_hdr->dst_addr, dst_addr, sizeof(ip_hdr->dst_addr));
+
+	return (uint16_t) (pkt_data_len + sizeof(struct ipv6_hdr));
+}
+
+uint16_t initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr, uint32_t dst_addr, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+	uint16_t *ptr16;
+	uint32_t ip_cksum;
+
+	/*
+	 * Initialize IP header.
+	 */
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct ipv4_hdr));
+
+	ip_hdr->version_ihl   = IP_VHL_DEF;
+	ip_hdr->type_of_service   = 0;
+	ip_hdr->fragment_offset = 0;
+	ip_hdr->time_to_live   = IP_DEFTTL;
+	ip_hdr->next_proto_id = IPPROTO_UDP;
+	ip_hdr->packet_id = 0;
+	ip_hdr->total_length   = rte_cpu_to_be_16(pkt_len);
+	ip_hdr->src_addr = rte_cpu_to_be_32(src_addr);
+	ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr);
+
+	/*
+	 * Compute IP header checksum.
+	 */
+	ptr16 = (uint16_t*) ip_hdr;
+	ip_cksum = 0;
+	ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
+	ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
+	ip_cksum += ptr16[4];
+	ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
+	ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
+
+	/*
+	 * Reduce 32 bit checksum to 16 bits and complement it.
+	 */
+	ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
+		(ip_cksum & 0x0000FFFF);
+	if (ip_cksum > 65535)
+		ip_cksum -= 65535;
+	ip_cksum = (~ip_cksum) & 0x0000FFFF;
+	if (ip_cksum == 0)
+		ip_cksum = 0xFFFF;
+	ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
+
+	return pkt_len;
+}
+
+
+
+/*
+ * The maximum number of segments per packet is used when creating
+ * scattered transmit packets composed of a list of mbufs.
+ */
+#define RTE_MAX_SEGS_PER_PKT 255 /**< pkt.nb_segs is a 8-bit unsigned char. */
+
+#define TXONLY_DEF_PACKET_LEN 64
+#define TXONLY_DEF_PACKET_LEN_128 128
+
+uint16_t tx_pkt_length = TXONLY_DEF_PACKET_LEN;
+uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT] = {
+		TXONLY_DEF_PACKET_LEN_128,
+};
+
+uint8_t  tx_pkt_nb_segs = 1;
+
+int generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst, struct ether_hdr* eth_hdr, uint8_t vlan_enabled, void *ip_hdr, uint8_t ipv4, struct udp_hdr *udp_hdr, int nb_pkt_per_burst)
+{
+	int i, nb_pkt = 0;
+	size_t eth_hdr_size;
+
+	struct rte_mbuf *pkt_seg;
+	struct rte_mbuf *pkt;
+
+	for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+		pkt = rte_pktmbuf_alloc(mp);
+		if (pkt == NULL) {
+		nomore_mbuf:
+			if (nb_pkt == 0)
+				return -1;
+			break;
+		}
+
+		pkt->pkt.data_len = tx_pkt_seg_lengths[0];
+		pkt_seg = pkt;
+		for (i = 1; i < tx_pkt_nb_segs; i++) {
+			pkt_seg->pkt.next = rte_pktmbuf_alloc(mp);
+			if (pkt_seg->pkt.next == NULL) {
+				pkt->pkt.nb_segs = i;
+				rte_pktmbuf_free(pkt);
+				goto nomore_mbuf;
+			}
+			pkt_seg = pkt_seg->pkt.next;
+			pkt_seg->pkt.data_len = tx_pkt_seg_lengths[i];
+		}
+		pkt_seg->pkt.next = NULL; /* Last segment of packet. */
+
+		/*
+		 * Copy headers in first packet segment(s).
+		 */
+		if (vlan_enabled)
+			eth_hdr_size = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_hdr_size = sizeof(struct ether_hdr);
+
+		copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0);
+
+		if (ipv4) {
+			copy_buf_to_pkt(ip_hdr, sizeof(struct ipv4_hdr), pkt, eth_hdr_size);
+			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size + sizeof(struct ipv4_hdr));
+		} else {
+			copy_buf_to_pkt(ip_hdr, sizeof(struct ipv6_hdr), pkt, eth_hdr_size);
+			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size + sizeof(struct ipv6_hdr));
+		}
+
+		/*
+		 * Complete first mbuf of packet and append it to the
+		 * burst of packets to be transmitted.
+		 */
+		pkt->pkt.nb_segs = tx_pkt_nb_segs;
+		pkt->pkt.pkt_len = tx_pkt_length;
+		pkt->pkt.vlan_macip.f.l2_len = eth_hdr_size;
+
+		if (ipv4) {
+			pkt->pkt.vlan_macip.f.vlan_tci  = ETHER_TYPE_IPv4;
+			pkt->pkt.vlan_macip.f.l3_len = sizeof(struct ipv4_hdr);
+
+			if (vlan_enabled)
+				pkt->ol_flags = PKT_RX_IPV4_HDR | PKT_RX_VLAN_PKT;
+			else
+				pkt->ol_flags = PKT_RX_IPV4_HDR;
+		}
+		else {
+			pkt->pkt.vlan_macip.f.vlan_tci  = ETHER_TYPE_IPv6;
+			pkt->pkt.vlan_macip.f.l3_len = sizeof(struct ipv6_hdr);
+
+			if (vlan_enabled)
+				pkt->ol_flags = PKT_RX_IPV6_HDR | PKT_RX_VLAN_PKT;
+			else
+				pkt->ol_flags = PKT_RX_IPV6_HDR;
+		}
+
+
+
+		pkts_burst[nb_pkt] = pkt;
+	}
+
+	return nb_pkt;
+}
+
diff --git a/app/test/packet_burst_generator.h b/app/test/packet_burst_generator.h
new file mode 100644
index 0000000..6b97860
--- /dev/null
+++ b/app/test/packet_burst_generator.h
@@ -0,0 +1,85 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PACKET_BURST_GENERATOR_H_
+#define PACKET_BURST_GENERATOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+
+
+#define IPV4_ADDR(a,b,c,d)(((a & 0xff) << 24) | ((b & 0xff)<< 16) | ((c & 0xff) << 8) | (d & 0xff))
+
+
+void initialize_eth_header(struct ether_hdr *eth_hdr,
+						   struct ether_addr *src_mac,
+						   struct ether_addr *dst_mac,
+						   uint8_t vlan_enabled,
+						   uint16_t van_id);
+
+uint16_t initialize_udp_header(struct udp_hdr *udp_hdr,
+							   uint16_t src_port,
+							   uint16_t dst_port,
+							   uint16_t pkt_data_len);
+
+
+uint16_t initialize_ipv6_header(struct ipv6_hdr *ip_hdr,
+								uint8_t *src_addr,
+								uint8_t *dst_addr,
+								uint16_t pkt_data_len);
+
+uint16_t initialize_ipv4_header(struct ipv4_hdr *ip_hdr,
+							  	uint32_t src_addr,
+							  	uint32_t dst_addr,
+							  	uint16_t pkt_data_len);
+
+int generate_packet_burst(struct rte_mempool *mp,
+						  struct rte_mbuf **pkts_burst,
+						  struct ether_hdr *eth_hdr,
+						  uint8_t vlan_enabled,
+						  void *ip_hdr, uint8_t ipv4,
+						  struct udp_hdr *udp_hdr,
+						  int nb_pkt_per_burst);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* PACKET_BURST_GENERATOR_H_ */
diff --git a/app/test/test.h b/app/test/test.h
index 1945d29..7213e1a 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -94,6 +94,7 @@ int test_pmd_ring(void);
 int test_ivshmem(void);
 int test_kvargs(void);
 int test_devargs(void);
+int test_link_bonding(void);
 
 int test_pci_run;
 
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
new file mode 100644
index 0000000..523a69b
--- /dev/null
+++ b/app/test/test_link_bonding.c
@@ -0,0 +1,4007 @@
+/*-
+ *   BSD LICENSE
+ * 
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ * 
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ * 
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_memory.h>
+#include <rte_bond.h>
+
+#include "virtual_pmd.h"
+#include "packet_burst_generator.h"
+
+#include "test.h"
+
+#define TEST_MAX_NUMBER_OF_PORTS (16)
+
+#define RX_RING_SIZE 128
+#define RX_FREE_THRESH 32
+#define RX_PTHRESH 8
+#define RX_HTHRESH 8
+#define RX_WTHRESH 0
+
+#define TX_RING_SIZE 512
+#define TX_FREE_THRESH 32
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+#define TX_RSBIT_THRESH 32
+#define TX_Q_FLAGS (ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOVLANOFFL |\
+	ETH_TXQ_FLAGS_NOXSUMSCTP | ETH_TXQ_FLAGS_NOXSUMUDP | \
+	ETH_TXQ_FLAGS_NOXSUMTCP)
+
+#define MBUF_SIZE 		(2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define MBUF_CACHE_SIZE (250)
+#define BURST_SIZE 		(32)
+
+#define DEFAULT_MBUF_DATA_SIZE 	(2048)
+#define RTE_TEST_RX_DESC_MAX 	(2048)
+#define RTE_TEST_TX_DESC_MAX 	(2048)
+#define MAX_PKT_BURST 			(512)
+#define DEF_PKT_BURST 			(16)
+
+#define BONDED_DEV_NAME ("unit_test_bonded_device")
+
+#define INVALID_SOCKET_ID (-1)
+#define INVALID_PORT_ID (-1)
+#define INVALID_BONDING_MODE (-1)
+
+
+uint8_t slave_mac[] = {0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 };
+uint8_t bonded_mac[] = {0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
+
+struct link_bonding_unittest_params {
+	int8_t bonded_port_id;
+	int8_t slave_port_ids[TEST_MAX_NUMBER_OF_PORTS];
+	uint8_t bonded_slave_count;
+	uint8_t bonding_mode;
+
+	uint16_t nb_rx_q;
+	uint16_t nb_tx_q;
+
+	struct rte_mempool *mbuf_pool;
+
+	struct ether_addr *default_slave_mac;
+	struct ether_addr *default_bonded_mac;
+
+	/* Packet Headers */
+	struct ether_hdr *pkt_eth_hdr;
+	struct ipv4_hdr *pkt_ipv4_hdr;
+	struct ipv6_hdr *pkt_ipv6_hdr;
+	struct udp_hdr *pkt_udp_hdr;
+
+};
+
+static struct ipv4_hdr pkt_ipv4_hdr;
+static struct ipv6_hdr pkt_ipv6_hdr;
+static struct udp_hdr pkt_udp_hdr;
+
+static struct link_bonding_unittest_params default_params  = {
+	.bonded_port_id = -1,
+	.slave_port_ids = { 0 },
+	.bonded_slave_count = 0,
+	.bonding_mode = BONDING_MODE_ROUND_ROBIN,
+
+	.nb_rx_q = 1,
+	.nb_tx_q = 1,
+
+	.mbuf_pool = NULL,
+
+	.default_slave_mac = (struct ether_addr *)slave_mac,
+	.default_bonded_mac = (struct ether_addr *)bonded_mac,
+
+	.pkt_eth_hdr = NULL,
+	.pkt_ipv4_hdr = &pkt_ipv4_hdr,
+	.pkt_ipv6_hdr = &pkt_ipv6_hdr,
+	.pkt_udp_hdr = &pkt_udp_hdr
+
+};
+
+static struct link_bonding_unittest_params *test_params = &default_params;
+
+static uint8_t src_mac[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
+static uint8_t dst_mac_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
+static uint8_t dst_mac_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAB };
+
+static uint32_t src_addr = IPV4_ADDR(192,168,1,98);
+static uint32_t dst_addr_0 = IPV4_ADDR(192,168,1,98);
+static uint32_t dst_addr_1 = IPV4_ADDR(193,166,1,99);
+
+static uint8_t src_ipv6_addr[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA  };
+static uint8_t dst_ipv6_addr_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA,  0xFF, 0xAA , 0xFF, 0xAA, 0xFF, 0xAA  };
+static uint8_t dst_ipv6_addr_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA , 0xFF, 0xAB  };
+
+static uint16_t src_port = 1024;
+static uint16_t dst_port_0 = 1024;
+static uint16_t dst_port_1 = 2024;
+
+static uint16_t vlan_id= 0x100;
+
+struct rte_eth_rxmode rx_mode = {
+	.max_rx_pkt_len = ETHER_MAX_LEN, /**< Default maximum frame length. */
+	.split_hdr_size = 0,
+	.header_split   = 0, /**< Header Split disabled. */
+	.hw_ip_checksum = 0, /**< IP checksum offload disabled. */
+	.hw_vlan_filter = 1, /**< VLAN filtering enabled. */
+	.hw_vlan_strip  = 1, /**< VLAN strip enabled. */
+	.hw_vlan_extend = 0, /**< Extended VLAN disabled. */
+	.jumbo_frame    = 0, /**< Jumbo Frame Support disabled. */
+	.hw_strip_crc   = 0, /**< CRC stripping by hardware disabled. */
+};
+
+struct rte_fdir_conf fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.flexbytes_offset = 0x6,
+	.drop_queue = 127,
+};
+
+static struct rte_eth_conf default_pmd_conf = {
+	.rxmode = {
+		.mq_mode = ETH_MQ_RX_NONE,
+		.max_rx_pkt_len = ETHER_MAX_LEN,
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload enabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.lpbk_mode = 0,
+};
+
+static const struct rte_eth_rxconf rx_conf_default = {
+	.rx_thresh = {
+		.pthresh = RX_PTHRESH,
+		.hthresh = RX_HTHRESH,
+		.wthresh = RX_WTHRESH,
+	},
+	.rx_free_thresh = RX_FREE_THRESH,
+	.rx_drop_en = 0,
+};
+
+static struct rte_eth_txconf tx_conf_default = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = TX_FREE_THRESH,
+	.tx_rs_thresh = TX_RSBIT_THRESH,
+	.txq_flags = TX_Q_FLAGS
+
+};
+
+static int
+configure_ethdev(uint8_t port_id, uint8_t start)
+{
+	int q_id;
+
+	if (rte_eth_dev_configure(port_id, test_params->nb_rx_q,
+			test_params->nb_tx_q, &default_pmd_conf) != 0) {
+		goto error;
+	}
+
+	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,
+				rte_eth_dev_socket_id(port_id), &rx_conf_default,
+				test_params->mbuf_pool) <
+				0) {
+			goto error;
+		}
+	}
+
+	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;
+		}
+	}
+	if (start) {
+		if (rte_eth_dev_start(port_id) < 0) {
+			printf("Failed to start device (%d).\n", port_id);
+			goto error;
+		}
+	}
+	return 0;
+
+error:
+	printf("Failed to configure ethdev %d", port_id);
+	return -1;
+}
+
+
+static int
+test_setup(void)
+{
+	int i, retval, nb_mbuf_per_pool;
+	struct ether_addr *mac_addr = (struct ether_addr *)slave_mac;
+
+	/* Allocate ethernet packet header with space for VLAN header */
+	test_params->pkt_eth_hdr = malloc(sizeof(struct ether_hdr) +
+			sizeof(struct vlan_hdr));
+	if (test_params->pkt_eth_hdr == NULL) {
+		printf("ethernet header struct allocation failed!\n");
+		return -1;
+	}
+
+
+	nb_mbuf_per_pool = RTE_TEST_RX_DESC_MAX + DEF_PKT_BURST +
+			RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;
+
+	test_params->mbuf_pool = rte_mempool_create("MBUF_POOL", nb_mbuf_per_pool,
+								   MBUF_SIZE, MBUF_CACHE_SIZE,
+								   sizeof(struct rte_pktmbuf_pool_private),
+								   rte_pktmbuf_pool_init, NULL,
+								   rte_pktmbuf_init, NULL,
+								   rte_socket_id(), 0);
+	if (test_params->mbuf_pool == NULL) {
+
+		printf("rte_mempool_create failed\n");
+		return -1;
+	}
+
+	/* Create / Initialize virtual eth devs */
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+
+		mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i;
+
+		test_params->slave_port_ids[i] = virtual_ethdev_create("slave_pmd_1",
+				mac_addr, rte_socket_id());
+		if (test_params->slave_port_ids[i] < 0) {
+			printf("Failed to create virtual pmd eth device.\n");
+			return -1;
+		}
+
+		retval = configure_ethdev(test_params->slave_port_ids[i], 1);
+		if (retval != 0) {
+			printf("Failed to configure virtual pmd eth device.\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+test_create_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	const uint8_t *slaves;
+
+	test_params->bonded_port_id = rte_eth_bond_create(BONDED_DEV_NAME,
+			test_params->bonding_mode, rte_socket_id());
+	if (test_params->bonded_port_id < 0) {
+		printf("\t Failed to create bonded device.\n");
+		return -1;
+	}
+
+	retval = configure_ethdev(test_params->bonded_port_id, 0);
+	if (retval != 0) {
+		printf("Failed to configure bonded pmd eth device.\n");
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count > 0) {
+		printf("Number of slaves is great than expected.\n");
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count > 0) {
+		printf("Number of active slaves is great than expected.\n");
+		return -1;
+	}
+
+
+	if (rte_eth_bond_mode_get(test_params->bonded_port_id) !=
+			test_params->bonding_mode) {
+		printf("Bonded device mode not as expected.\n");
+		return -1;
+
+	}
+
+	return 0;
+}
+
+
+static int
+test_create_bonded_device_with_invalid_params(void)
+{
+	int port_id;
+
+	test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN;
+
+	/* Invalid name */
+	port_id = rte_eth_bond_create(NULL, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	test_params->bonding_mode = INVALID_BONDING_MODE;
+
+	/* Invalid bonding mode */
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN;
+
+	/* Invalid socket id */
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			INVALID_SOCKET_ID);
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_add_slave_to_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	const uint8_t *slaves;
+
+	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;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	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;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count != 0) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				current_slave_count, 0);
+		return -1;
+	}
+
+	test_params->bonded_slave_count++;
+
+	return 0;
+}
+
+static int
+test_add_slave_to_invalid_bonded_device(void)
+{
+	int retval;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_slave_add(test_params->bonded_port_id + 5,
+			test_params->slave_port_ids[test_params->bonded_slave_count]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_slave_add(test_params->slave_port_ids[0],
+			test_params->slave_port_ids[test_params->bonded_slave_count]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+test_remove_slave_from_bonded_device(void)
+{
+	int retval, current_slave_count;
+	struct ether_addr read_mac_addr, *mac_addr;
+	const uint8_t *slaves;
+
+	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;
+	}
+
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	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;
+	}
+
+
+	mac_addr = (struct ether_addr *)slave_mac;
+	mac_addr->addr_bytes[ETHER_ADDR_LEN-1] =
+			test_params->slave_port_ids[test_params->bonded_slave_count-1];
+
+	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;
+	}
+
+	rte_eth_stats_reset(
+			test_params->slave_port_ids[test_params->bonded_slave_count-1]);
+
+	virtual_ethdev_simulate_link_status_interrupt(test_params->bonded_port_id,
+			0);
+
+	test_params->bonded_slave_count--;
+
+	return 0;
+}
+
+static int
+test_remove_slave_from_invalid_bonded_device(void)
+{
+	int retval;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_slave_remove(test_params->bonded_port_id + 5,
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_slave_remove(test_params->slave_port_ids[0],
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_add_already_bonded_slave_to_bonded_device(void)
+{
+	int retval, port_id, current_slave_count;
+	const uint8_t *slaves;
+
+	test_add_slave_to_bonded_device();
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count != 1) {
+		printf("Number of slaves (%d) is not that expected (%d).\n",
+				current_slave_count, 1);
+		return -1;
+	}
+
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id < 0) {
+		printf("Failed to create bonded device.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_slave_add(port_id,
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Added slave (%d) to bonded port (%d) unexpectedly.\n",
+				test_params->slave_port_ids[test_params->bonded_slave_count-1],
+				port_id);
+		return -1;
+	}
+
+	return test_remove_slave_from_bonded_device();
+}
+
+
+static int
+test_get_slaves_from_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	const uint8_t *slaves;
+
+	retval = test_add_slave_to_bonded_device();
+	if (retval != 0) {
+		return -1;
+	}
+
+
+	/* Invalid port id */
+	current_slave_count = rte_eth_bond_slaves_get(INVALID_PORT_ID, &slaves);
+	if (current_slave_count >= 0) {
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(INVALID_PORT_ID,
+			&slaves);
+	if (current_slave_count >= 0) {
+		return -1;
+	}
+
+	/* Invalid slaves pointer */
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			NULL);
+	if (current_slave_count >= 0) {
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, NULL);
+	if (current_slave_count >= 0) {
+		return -1;
+	}
+
+	/* non bonded device*/
+	current_slave_count = rte_eth_bond_slaves_get(
+			test_params->slave_port_ids[0], NULL);
+	if (current_slave_count >= 0) {
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->slave_port_ids[0],	NULL);
+	if (current_slave_count >= 0) {
+		return -1;
+	}
+
+	retval = test_remove_slave_from_bonded_device();
+	if (retval != 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+test_add_remove_multiple_slaves_to_from_bonded_device(void)
+{
+	int retval, i;
+
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			return -1;
+		}
+	}
+
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		retval = test_remove_slave_from_bonded_device();
+		if (retval != 0) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void
+enable_bonded_slaves(void)
+{
+	int i;
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 1);
+	}
+}
+
+static int
+test_start_bonded_device(void)
+{
+	struct rte_eth_link link_status;
+
+	int retval, current_slave_count, current_bonding_mode, primary_port;
+	const uint8_t *slaves;
+
+	/* Add slave to bonded device*/
+	retval = test_add_slave_to_bonded_device();
+	if (retval != 0) {
+		return -1;
+
+	}
+	retval = rte_eth_dev_start(test_params->bonded_port_id);
+	if (retval != 0) {
+		printf("Failed to start bonded pmd eth device.\n");
+		return -1;
+	}
+
+	/* Change link status of virtual pmd so it will be added to the active slave
+	 *  list of the bonded device*/
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[test_params->bonded_slave_count-1], 1);
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of active slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id);
+	if (current_bonding_mode != test_params->bonding_mode) {
+		printf("Bonded device mode (%d) is not expected value (%d).\n",
+				current_bonding_mode, test_params->bonding_mode);
+		return -1;
+
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[0]) {
+		printf("Primary port (%d) is not expected value (%d).\n",
+				primary_port, test_params->slave_port_ids[0]);
+		return -1;
+
+	}
+
+	rte_eth_link_get(test_params->bonded_port_id, &link_status);
+	if (!link_status.link_status) {
+		printf("Bonded port (%d) status (%d) is not expected value (%d).\n",
+				test_params->bonded_port_id, link_status.link_status, 1);
+		return -1;
+
+	}
+
+	return 0;
+}
+
+static int
+test_stop_bonded_device(void)
+{
+	int current_slave_count;
+	const uint8_t *slaves;
+
+	struct rte_eth_link link_status;
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	rte_eth_link_get(test_params->bonded_port_id, &link_status);
+	if (link_status.link_status) {
+		printf("Bonded port (%d) status (%d) is not expected value (%d).\n",
+				test_params->bonded_port_id, link_status.link_status, 0);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count != 0) {
+		printf("Number of active slaves (%d) is not expected value (%d).\n",
+				current_slave_count, 0);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int remove_slaves_and_stop_bonded_device(void)
+{
+	/* Clean up and remove slaves from bonded device */
+	while (test_params->bonded_slave_count > 0) {
+		if (test_remove_slave_from_bonded_device() != 0) {
+			printf("test_remove_slave_from_bonded_device failed\n");
+			return -1;
+		}
+	}
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+	rte_eth_stats_reset(test_params->bonded_port_id);
+	rte_eth_bond_mac_address_reset(test_params->bonded_port_id);
+
+	return 0;
+}
+
+static int
+test_set_bonding_mode(void)
+{
+	int i;
+	int retval, bonding_mode;
+
+	int bonding_modes[] = { BONDING_MODE_ROUND_ROBIN,
+							BONDING_MODE_ACTIVE_BACKUP,
+							BONDING_MODE_BALANCE,
+							BONDING_MODE_BROADCAST };
+
+	/* Test supported link bonding modes */
+	for (i = 0; i < (int)RTE_DIM(bonding_modes);	i++) {
+		/* Invalid port ID */
+		retval = rte_eth_bond_mode_set(INVALID_PORT_ID, bonding_modes[i]);
+		if (retval == 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					INVALID_PORT_ID);
+			return -1;
+		}
+
+		/* Non bonded device */
+		retval = rte_eth_bond_mode_set(test_params->slave_port_ids[0],
+				bonding_modes[i]);
+		if (retval == 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					test_params->slave_port_ids[0]);
+			return -1;
+		}
+
+		retval = rte_eth_bond_mode_set(test_params->bonded_port_id,
+				bonding_modes[i]);
+		if (retval != 0) {
+			printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+					test_params->bonded_port_id, bonding_modes[i]);
+			return -1;
+		}
+
+		bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id);
+		if (bonding_mode != bonding_modes[i]) {
+			printf("Link bonding mode (%d) of port (%d) is not expected value "
+					"(%d).\n", bonding_mode, test_params->bonded_port_id,
+					bonding_modes[i]);
+			return -1;
+		}
+
+
+		/* Invalid port ID */
+		bonding_mode = rte_eth_bond_mode_get(INVALID_PORT_ID);
+		if (bonding_mode >= 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					INVALID_PORT_ID);
+			return -1;
+		}
+
+
+		/* Non bonded device */
+		bonding_mode = rte_eth_bond_mode_get(test_params->slave_port_ids[0]);
+		if (bonding_mode >= 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					test_params->slave_port_ids[0]);
+			return -1;
+		}
+
+	}
+
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_set_primary_slave(void)
+{
+	int i, j, retval;
+	struct ether_addr read_mac_addr;
+	struct ether_addr *expected_mac_addr;
+
+	/* Add 4 slaves to bonded device */
+	for (i = test_params->bonded_slave_count; i < 4; i++) {
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave to bonded device.\n");
+			return -1;
+		}
+	}
+	retval = rte_eth_bond_mode_set(test_params->bonded_port_id,
+			BONDING_MODE_ROUND_ROBIN);
+	if (retval != 0) {
+		printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+				test_params->bonded_port_id, BONDING_MODE_ROUND_ROBIN);
+		return -1;
+	}
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_primary_set(INVALID_PORT_ID,
+			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) {
+			printf("Failed to set bonded port (%d) primary port to (%d)\n",
+					test_params->bonded_port_id,
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+
+		retval = rte_eth_bond_primary_get(test_params->bonded_port_id);
+		if (retval < 0) {
+			printf("Failed to read primary port from bonded port (%d)\n",
+					test_params->bonded_port_id);
+			return -1;
+		}
+		else if (retval != test_params->slave_port_ids[i]) {
+			printf("Bonded port (%d) primary port (%d) not expected value "
+					"(%d)\n", test_params->bonded_port_id, retval,
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+
+		/* 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;
+		}
+
+		expected_mac_addr = (struct ether_addr *)&slave_mac;
+		expected_mac_addr->addr_bytes[ETHER_ADDR_LEN-1] =
+				test_params->slave_port_ids[i];
+
+		/* Check primary slave MAC */
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(expected_mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("bonded port mac address not set to that of primary port\n");
+			return -1;
+		}
+
+		/* Check bonded MAC */
+		rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+		if (memcmp(&read_mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("bonded port mac address not set to that of primary port\n");
+			return -1;
+		}
+
+		/* Check other slaves MACs */
+		for (j = 0; j < 4; j++) {
+			if (j != i) {
+				rte_eth_macaddr_get(test_params->slave_port_ids[j],
+						&read_mac_addr);
+				if (memcmp(expected_mac_addr, &read_mac_addr,
+						sizeof(read_mac_addr))) {
+					printf("slave port mac address not set to that of primary "
+							"port\n");
+					return -1;
+				}
+			}
+		}
+	}
+
+
+	/* Test with none existent port */
+	retval = rte_eth_bond_primary_get(test_params->bonded_port_id + 10);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	/* Test with slave port */
+	retval = rte_eth_bond_primary_get(test_params->slave_port_ids[0]);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	if (remove_slaves_and_stop_bonded_device() != 0)
+		return -1;
+
+	/* No slaves  */
+	retval = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_set_explicit_bonded_mac(void)
+{
+	int i, retval;
+	struct ether_addr read_mac_addr;
+	struct ether_addr *mac_addr;
+
+	uint8_t explicit_bonded_mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01 };
+
+	mac_addr = (struct ether_addr *)explicit_bonded_mac;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_mac_address_set(INVALID_PORT_ID, mac_addr);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_mac_address_set(test_params->slave_port_ids[0],
+			mac_addr);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* NULL MAC address */
+	retval = rte_eth_bond_mac_address_set(test_params->bonded_port_id, NULL);
+	if (retval == 0) {
+		printf("Expected call to failed as NULL MAC specified\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			mac_addr);
+	if (retval != 0) {
+		printf("Failed to set MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* Add 4 slaves to bonded device */
+	for (i = test_params->bonded_slave_count; i < 4; i++) {
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave to bonded device.\n");
+			return -1;
+		}
+	}
+
+	/* Check bonded MAC */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &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;
+	}
+
+	/* Check other slaves MACs */
+	for (i = 0; i < 4; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port mac address not set to that of primary port\n");
+			return -1;
+		}
+	}
+
+	/* test resetting mac address on bonded device */
+	if (rte_eth_bond_mac_address_reset(test_params->bonded_port_id) != 0) {
+		printf("Failed to reset MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+
+		return -1;
+	}
+
+	if (rte_eth_bond_mac_address_reset(test_params->slave_port_ids[0]) == 0) {
+		printf("Reset MAC address on bonded port (%d) unexpectedly\n",
+				test_params->slave_port_ids[1]);
+
+		return -1;
+	}
+
+	/* test resetting mac address on bonded device with no slaves */
+
+	if (remove_slaves_and_stop_bonded_device() != 0) {
+		return -1;
+	}
+
+	if (rte_eth_bond_mac_address_reset(test_params->bonded_port_id) != 0) {
+		printf("Failed to reset MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+initialize_bonded_device_with_slaves(uint8_t bonding_mode,
+		uint8_t number_of_slaves, uint8_t enable_slave)
+{
+	int retval;
+
+	/* configure bonded device */
+	retval = configure_ethdev(test_params->bonded_port_id, 0);
+	if (retval != 0) {
+		printf("Failed to configure bonding port (%d) in mode %d with (%d) "
+				"slaves.\n", test_params->bonded_port_id, bonding_mode,
+				number_of_slaves);
+		return -1;
+	}
+
+	while (number_of_slaves > test_params->bonded_slave_count) {
+		/* Add slaves to bonded device */
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave (%d to  bonding port (%d).\n",
+					test_params->bonded_slave_count -1,
+					test_params->bonded_port_id);
+			return -1;
+		}
+	}
+
+	/* Set link bonding mode  */
+	retval = rte_eth_bond_mode_set(test_params->bonded_port_id, bonding_mode);
+	if (retval != 0) {
+		printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+				test_params->bonded_port_id, bonding_mode);
+		return -1;
+	}
+
+	retval = rte_eth_dev_start(test_params->bonded_port_id);
+	if (retval != 0) {
+		printf("Failed to start bonded pmd eth device.\n");
+		return -1;
+	}
+
+	if (enable_slave) {
+		enable_bonded_slaves();
+	}
+
+	return 0;
+}
+
+static int
+test_adding_slave_after_bonded_device_started(void)
+{
+	int i;
+
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 0) !=
+			0)
+		return -1;
+
+	/* Enabled slave devices */
+	for (i = 0; i < test_params->bonded_slave_count + 1; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				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_params->bonded_slave_count++;
+
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+generate_test_burst(struct rte_mbuf **pkts_burst, uint16_t burst_size,
+		uint8_t vlan, uint8_t ipv4, uint8_t toggle_dst_mac,
+		uint8_t toggle_ip_addr, uint8_t toggle_udp_port)
+{
+	uint16_t pktlen, generated_burst_size;
+	void * ip_hdr;
+
+	if (toggle_dst_mac)
+		initialize_eth_header(test_params->pkt_eth_hdr,
+				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
+				vlan, vlan_id);
+	else
+		initialize_eth_header(test_params->pkt_eth_hdr,
+				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+				vlan, vlan_id);
+
+
+	if (toggle_udp_port)
+		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+				dst_port_1, 64);
+	else
+		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+				dst_port_0, 64);
+
+	if (ipv4) {
+		if (toggle_ip_addr)
+			pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+					dst_addr_1, pktlen);
+		else
+			pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+					dst_addr_0, pktlen);
+
+		ip_hdr = test_params->pkt_ipv4_hdr;
+	}
+	else {
+		if (toggle_ip_addr)
+			pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr,
+					(uint8_t*)src_ipv6_addr, (uint8_t*)dst_ipv6_addr_1, pktlen);
+		else
+			pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr,
+					(uint8_t*)src_ipv6_addr, (uint8_t*)dst_ipv6_addr_0, pktlen);
+
+		ip_hdr = test_params->pkt_ipv6_hdr;
+	}
+
+	/* Generate burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, vlan, ip_hdr, ipv4,
+			test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size) {
+		printf("Failed to generate packet burst");
+		return -1;
+	}
+
+	return generated_burst_size;
+}
+
+/** Round Robin Mode Tests */
+
+static int
+test_roundrobin_tx_burst(void)
+{
+	int i, burst_size, nb_tx;
+	struct rte_mbuf *pkt_burst[MAX_PKT_BURST];
+	struct rte_eth_stats port_stats;
+
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 2, 1)
+			!= 0)
+		return -1;
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0) != burst_size)
+		return -1;
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst,
+			burst_size);
+	if (nb_tx != burst_size) {
+		return -1;
+	}
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i <test_params-> bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (port_stats.opackets !=
+				(uint64_t)burst_size / test_params->bonded_slave_count) {
+			printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+					test_params->bonded_port_id,
+					(unsigned int)port_stats.opackets,
+					burst_size / test_params->bonded_slave_count);
+			return -1;
+		}
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst,
+			burst_size);
+	if (nb_tx != 0) {
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_roundrobin_rx_burst_on_single_slave(void)
+{
+	struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+
+	struct rte_eth_stats port_stats;
+
+	int i, j, nb_rx, burst_size = 25;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1) !=
+			0)
+		return -1;
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(gen_pkt_burst, burst_size, 0, 1, 0, 0, 0) !=
+			burst_size)
+		return -1;
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		/* Add rx data to slave */
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[0], burst_size);
+
+		/* Call rx burst on bonded device */
+		/* Send burst on bonded port */
+		nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+				MAX_PKT_BURST);
+		if (nb_rx != burst_size) {
+			printf("round-robin rx burst failed");
+			return -1;
+		}
+
+		/* Verify bonded device rx count */
+		rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+		if (port_stats.ipackets != (uint64_t)burst_size) {
+			printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+					test_params->bonded_port_id,
+					(unsigned int)port_stats.ipackets, burst_size);
+			return -1;
+		}
+
+
+		/* Verify bonded slave devices rx count */
+		/* Verify slave ports tx stats */
+		for (j = 0; j < test_params->bonded_slave_count; j++) {
+			rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);
+
+			if (i == j) {
+				if (port_stats.ipackets != (uint64_t)burst_size) {
+					printf("Slave Port (%d) ipackets value (%u) not as expected"
+							" (%d)\n", test_params->slave_port_ids[i],
+							(unsigned int)port_stats.ipackets, burst_size);
+					return -1;
+				}
+			} else {
+				if (port_stats.ipackets != 0) {
+					printf("Slave Port (%d) ipackets value (%u) not as expected"
+							" (%d)\n", test_params->slave_port_ids[i],
+							(unsigned int)port_stats.ipackets, 0);
+					return -1;
+				}
+			}
+
+			/* Reset bonded slaves stats */
+			rte_eth_stats_reset(test_params->slave_port_ids[j]);
+		}
+		/* reset bonded device stats */
+		rte_eth_stats_reset(test_params->bonded_port_id);
+	}
+
+	/* free mbufs */
+	for (i = 0; i < MAX_PKT_BURST; i++) {
+		if (gen_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(gen_pkt_burst[i]);
+
+		if (rx_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(rx_pkt_burst[i]);
+	}
+
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT (3)
+
+static int
+test_roundrobin_rx_burst_on_multiple_slaves(void)
+{
+	struct rte_mbuf *gen_pkt_burst[TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT]
+	                               [MAX_PKT_BURST];
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	int burst_size[TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT] = { 15, 13, 36 };
+	int i, nb_rx;
+
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1) !=
+			0)
+		return -1;
+
+	/* Generate test bursts of packets to transmit */
+	for (i = 0; i < TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size[i], 0, 1, 0, 0,
+				0) != burst_size[i])
+			return -1;
+	}
+
+	/* Add rx data to slaves */
+	for (i = 0; i < TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT; i++) {
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size[i]);
+	}
+
+	/* Call rx burst on bonded device */
+	/* Send burst on bonded port */
+	nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+	if (nb_rx != burst_size[0] + burst_size[1] + burst_size[2]) {
+		printf("round-robin rx burst failed (%d != %d)\n", nb_rx,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size[0] + burst_size[1] +
+			burst_size[2])) {
+		printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.ipackets,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+
+	/* Verify bonded slave devices rx counts */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.ipackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.ipackets, burst_size[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[2]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[2],
+				(unsigned int)port_stats.ipackets, burst_size[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.ipackets != 0) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[3],
+				(unsigned int)port_stats.ipackets, 0);
+		return -1;
+	}
+
+	/* free mbufs */
+	for (i = 0; i < MAX_PKT_BURST; i++) {
+		if (rx_pkt_burst[i] != NULL) {
+			rte_pktmbuf_free(rx_pkt_burst[i]);
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_roundrobin_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_2;
+
+	int i, retval;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[2], &expected_mac_addr_2);
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1)
+			!= 0)
+		return -1;
+
+	/* Verify that all MACs are the same as first slave added to bonded dev */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of primary "
+					"port\n", test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	retval = rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[2]);
+	if (retval != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address has changed to that of primary "
+					"port without stop/start toggle of bonded device\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagate to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_2, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary "
+				"port\n", test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_2, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary "
+					"port\n", test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary "
+				"port\n",test_params-> slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary "
+					"port\n",test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_roundrobin_verify_promiscuous_enable_disable(void)
+{
+	int i, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1)!= 0)
+		return -1;
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(test_params->slave_port_ids[i]);
+		if (promiscuous_en != 1) {
+			printf("slave port (%d) promiscuous mode not enabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_RR_LINK_STATUS_SLAVE_COUNT (4)
+#define TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT (2)
+
+static int
+test_roundrobin_verify_slave_link_status_change_behaviour(void)
+{
+	struct rte_mbuf *tx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_mbuf *gen_pkt_burst[TEST_RR_LINK_STATUS_SLAVE_COUNT]
+	                               [MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+
+	struct rte_eth_stats port_stats;
+	const uint8_t *slaves;
+
+	int i, burst_size, slave_count;
+
+	/* NULL all pointers in array to simplify cleanup */
+	memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst));
+
+	/* Initialize bonded device with TEST_RR_LINK_STATUS_SLAVE_COUNT slaves
+	 * in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN,
+			TEST_RR_LINK_STATUS_SLAVE_COUNT, 1)!= 0)
+		return -1;
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != TEST_RR_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of slaves (%d) is not as expected (%d).\n", slave_count,
+				TEST_RR_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != TEST_RR_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, TEST_RR_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	/* Set 2 slaves eth_devs link status to down */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves) != TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT);
+		return -1;
+	}
+
+	burst_size = 21;
+
+	/* Verify that pkts are not sent on slaves with link status down:
+	 *
+	 * 1. Generate test burst of traffic
+	 * 2. Transmit burst on bonded eth_dev
+	 * 3. Verify stats for bonded eth_dev (opackets = burst_size)
+	 * 4. Verify stats for slave eth_devs (s0 = 11, s1 = 0, s2 = 10, s3 = 0)
+	 */
+	if (generate_test_burst(tx_pkt_burst, burst_size, 0, 1, 0, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, tx_pkt_burst,
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != 11) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != 10) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	/* Verify that pkts are not sent on slaves with link status down:
+	 *
+	 * 1. Generate test bursts of traffic
+	 * 2. Add bursts on to virtual eth_devs
+	 * 3. Rx burst on bonded eth_dev, expected (burst_ size *
+	 * 		TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT) received
+	 * 4. Verify stats for bonded eth_dev
+	 * 6. Verify stats for slave eth_devs (s0 = 11, s1 = 0, s2 = 10, s3 = 0)
+	 */
+	for (i = 0; i < TEST_RR_LINK_STATUS_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0)
+				!= burst_size) {
+			return -1;
+		}
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size);
+	}
+
+	if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST) != burst_size + burst_size) {
+		printf("rte_eth_rx_burst\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.ipackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* free mbufs */
+	for (i = 0; i < MAX_PKT_BURST; i++) {
+		if (rx_pkt_burst[i] != NULL) {
+			rte_pktmbuf_free(rx_pkt_burst[i]);
+		}
+		if (gen_pkt_burst[1][i] != NULL) {
+			rte_pktmbuf_free(gen_pkt_burst[1][i]);
+		}
+		if (gen_pkt_burst[3][i] != NULL) {
+			rte_pktmbuf_free(gen_pkt_burst[1][i]);
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+/** Active Backup Mode Tests */
+
+static int
+test_activebackup_tx_burst(void)
+{
+	int i, retval, pktlen, primary_port, burst_size, generated_burst_size, nb_tx;
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);
+	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+			dst_port_0, 16);
+	pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+			dst_addr_0, pktlen);
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate a burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr,
+			1, test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size) {
+		return -1;
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != burst_size) {
+		return -1;
+	}
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (test_params->slave_port_ids[i] == primary_port) {
+			if (port_stats.opackets != (uint64_t)burst_size) {
+				printf("Slave Port (%d) opackets value (%u) not as expected "
+						"(%d)\n", test_params->bonded_port_id,
+						(unsigned int)port_stats.opackets,
+						burst_size / test_params->bonded_slave_count);
+				return -1;
+			}
+		} else {
+			if (port_stats.opackets != 0) {
+				printf("Slave Port (%d) opackets value (%u) not as expected "
+						"(%d)\n", test_params->bonded_port_id,
+						(unsigned int)port_stats.opackets, 0);
+				return -1;
+			}
+		}
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != 0) {
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT (4)
+
+static int
+test_activebackup_rx_burst(void)
+{
+	struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+
+	struct rte_eth_stats port_stats;
+
+	int primary_port;
+
+	int i, j, nb_rx, burst_size = 17;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP,
+			TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT, 1)
+			!= 0)
+		return -1;
+
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port < 0) {
+		printf("failed to get primary slave for bonded port (%d)",
+				test_params->bonded_port_id);
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		/* Generate test bursts of packets to transmit */
+		if (generate_test_burst(&gen_pkt_burst[0], burst_size, 0, 1, 0, 0, 0)
+				!= burst_size) {
+			return -1;
+		}
+
+		/* Add rx data to slave */
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[0], burst_size);
+
+		/* Call rx burst on bonded device */
+		nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0,
+				&rx_pkt_burst[0], MAX_PKT_BURST);
+		if (nb_rx < 0) {
+			printf("rte_eth_rx_burst failed\n");
+			return -1;
+		}
+
+		if (test_params->slave_port_ids[i] == primary_port) {
+			/* Verify bonded device rx count */
+			rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+			if (port_stats.ipackets != (uint64_t)burst_size) {
+				printf("Bonded Port (%d) ipackets value (%u) not as expected "
+						"(%d)\n", test_params->bonded_port_id,
+						(unsigned int)port_stats.ipackets, burst_size);
+				return -1;
+			}
+
+			/* Verify bonded slave devices rx count */
+			for (j = 0; j < test_params->bonded_slave_count; j++) {
+				rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);
+				if (i == j) {
+					if (port_stats.ipackets != (uint64_t)burst_size) {
+						printf("Slave Port (%d) ipackets value (%u) not as "
+								"expected (%d)\n",
+								test_params->slave_port_ids[i],
+								(unsigned int)port_stats.ipackets, burst_size);
+						return -1;
+					}
+				} else {
+					if (port_stats.ipackets != 0) {
+						printf("Slave Port (%d) ipackets value (%u) not as "
+								"expected (%d)\n",
+								test_params->slave_port_ids[i],
+								(unsigned int)port_stats.ipackets, 0);
+						return -1;
+					}
+				}
+			}
+		} else {
+			for (j = 0; j < test_params->bonded_slave_count; j++) {
+				rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);
+				if (port_stats.ipackets != 0) {
+					printf("Slave Port (%d) ipackets value (%u) not as expected"
+							" (%d)\n", test_params->slave_port_ids[i],
+							(unsigned int)port_stats.ipackets, 0);
+					return -1;
+				}
+			}
+		}
+
+		/* free mbufs */
+		for (i = 0; i < MAX_PKT_BURST; i++) {
+			if (rx_pkt_burst[i] != NULL) {
+				rte_pktmbuf_free(rx_pkt_burst[i]);
+				rx_pkt_burst[i] = NULL;
+			}
+		}
+
+		/* reset bonded device stats */
+		rte_eth_stats_reset(test_params->bonded_port_id);
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_activebackup_verify_promiscuous_enable_disable(void)
+{
+	int i, primary_port, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP, 4, 1)
+			!= 0)
+		return -1;
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port < 0) {
+		printf("failed to get primary slave for bonded port (%d)",
+				test_params->bonded_port_id);
+	}
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (primary_port == test_params->slave_port_ids[i]) {
+			if (promiscuous_en != 1) {
+				printf("slave port (%d) promiscuous mode not enabled\n",
+						test_params->slave_port_ids[i]);
+				return -1;
+			}
+		} else {
+			if (promiscuous_en != 0) {
+				printf("slave port (%d) promiscuous mode enabled\n",
+						test_params->slave_port_ids[i]);
+				return -1;
+			}
+		}
+
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_activebackup_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1);
+
+	/* Initialize bonded device with 2 slaves in active backup mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP, 2, 1)
+			!= 0)
+		return -1;
+
+	/* Verify that bonded MACs is that of first slave and that the other slave
+	 * MAC hasn't been changed */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	if (rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[1]) != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagated to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of bonded port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of bonded port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_activebackup_verify_slave_link_status_change_failover(void)
+{
+	struct rte_mbuf *pkt_burst[TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT]
+	                           [MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	const uint8_t *slaves;
+
+	int i, j, burst_size, slave_count, primary_port;
+
+	burst_size = 21;
+
+	memset(pkt_burst, 0, sizeof(pkt_burst));
+
+	/* Generate packet burst for testing */
+	if (generate_test_burst(&pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP,
+			TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT, 1)
+			!= 0)
+		return -1;
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != 4) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[0]) {
+		printf("Primary port not as expected");
+	}
+
+	/* Bring 2 slaves down and verify active slave count */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves)
+			!= 2) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 2);
+		return -1;
+	}
+
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 1);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 1);
+
+
+	/* Bring primary port down, verify that active slave count is 3 and primary
+	 *  has changed */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[0], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves)
+			!= 3) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 3);
+		return -1;
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[2]) {
+		printf("Primary port not as expected");
+	}
+
+	/* Verify that pkts are sent on new primary slave */
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[0][0], burst_size)
+			!= burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	/* Generate packet burst for testing */
+
+	for (i = 0; i < TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0) !=
+				burst_size) {;
+			return -1;
+		}
+		virtual_ethdev_add_mbufs_to_rx_queue(
+			test_params->slave_port_ids[i], &pkt_burst[i][0], burst_size);
+	}
+
+	if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST) != burst_size) {
+		printf("rte_eth_rx_burst\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.ipackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	/* free mbufs */
+
+	for (i = 0; i < TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(pkt_burst[i][j]);
+				pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+/** Balance Mode Tests */
+
+static int
+test_balance_xmit_policy_configuration(void)
+{
+	int retval;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP,
+			2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	/* Invalid port id */
+	retval = rte_eth_bond_xmit_policy_set(INVALID_PORT_ID,
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Set xmit policy on non bonded device */
+	retval = rte_eth_bond_xmit_policy_set(test_params->slave_port_ids[0],
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+	if (rte_eth_bond_xmit_policy_get(test_params->bonded_port_id) !=
+			BALANCE_XMIT_POLICY_LAYER2) {
+		printf("balance xmit policy not as expected.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER23);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+	if (rte_eth_bond_xmit_policy_get(test_params->bonded_port_id) !=
+			BALANCE_XMIT_POLICY_LAYER23) {
+		printf("balance xmit policy not as expected.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER34);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+	if (rte_eth_bond_xmit_policy_get(test_params->bonded_port_id) !=
+			BALANCE_XMIT_POLICY_LAYER34) {
+		printf("balance xmit policy not as expected.\n");
+		return -1;
+	}
+
+	// Invalid port id
+	if (rte_eth_bond_xmit_policy_get(INVALID_PORT_ID) >= 0) {
+		return -1;
+	}
+
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT (2)
+
+static int
+test_balance_l2_tx_burst(void)
+{
+	struct rte_mbuf *pkts_burst[TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT]
+	                            [MAX_PKT_BURST];
+	int burst_size[TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT] = { 10, 15 };
+
+	uint16_t pktlen;
+
+	int retval, i;
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE,
+			TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);
+	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+			dst_port_0, 16);
+	pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+			dst_addr_0, pktlen);
+
+	/* Generate a burst 1 of packets to transmit */
+	if (generate_packet_burst(test_params->mbuf_pool, &pkts_burst[0][0],
+			test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, 1,
+			test_params->pkt_udp_hdr, burst_size[0]) != burst_size[0]) {
+		return -1;
+	}
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1, 0, 0);
+
+	/* Generate a burst 2 of packets to transmit */
+	if (generate_packet_burst(test_params->mbuf_pool, &pkts_burst[1][0],
+			test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, 1,
+			test_params->pkt_udp_hdr, burst_size[1]) != burst_size[1]) {
+		return -1;
+	}
+
+	/* Send burst 1 on bonded port */
+	for (i = 0; i < TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT; i++) {
+		if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkts_burst[i][0],
+			burst_size[i]) != burst_size[i]) {
+		return -1;
+	}
+	}
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size[0] + burst_size[1])) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				(unsigned int)port_stats.opackets, burst_size[0] + burst_size[1]);
+		return -1;
+	}
+
+
+	/* Verify slave ports tx stats */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.opackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1], (
+						unsigned int)port_stats.opackets, burst_size[1]);
+		return -1;
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkts_burst[0][0],
+			burst_size[0]) != 0) {
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+balance_l23_tx_burst(uint8_t vlan_enabled, uint8_t ipv4,
+		uint8_t toggle_mac_addr, uint8_t toggle_ip_addr)
+{
+	int retval, i;
+	int burst_size_1, burst_size_2, nb_tx_1, nb_tx_2;
+
+	struct rte_mbuf *pkts_burst_1[MAX_PKT_BURST];
+	struct rte_mbuf *pkts_burst_2[MAX_PKT_BURST];
+
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER23);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+	burst_size_1 = 20;
+	burst_size_2 = 10;
+
+	if (burst_size_1 > MAX_PKT_BURST || burst_size_2 > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkts_burst_1, burst_size_1, vlan_enabled, ipv4,
+			0, 0, 0) != burst_size_1)
+		return -1;
+
+	if (generate_test_burst(pkts_burst_2, burst_size_2, vlan_enabled, ipv4,
+			toggle_mac_addr, toggle_ip_addr, 0) != burst_size_2)
+		return -1;
+
+	/* Send burst 1 on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != burst_size_1) {
+		return -1;
+	}
+	/* Send burst 2 on bonded port */
+	nb_tx_2 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_2,
+			burst_size_2);
+	if (nb_tx_2 != burst_size_2) {
+		return -1;
+	}
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(nb_tx_1 + nb_tx_2)) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				(unsigned int)port_stats.opackets, nb_tx_1 + nb_tx_2);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_1) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.opackets, nb_tx_1);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_2) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.opackets, nb_tx_2);
+		return -1;
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != 0) {
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_l23_tx_burst_ipv4_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(0, 1, 1, 0);
+}
+
+static int
+test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(1, 1, 0, 1);
+}
+
+static int
+test_balance_l23_tx_burst_ipv6_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(0, 0, 0, 1) ;
+}
+
+static int
+test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(1, 0, 0, 1);
+}
+
+static int
+test_balance_l23_tx_burst_toggle_mac_addr(void)
+{
+	return balance_l23_tx_burst(0, 0, 1, 0);
+}
+
+static int
+balance_l34_tx_burst(uint8_t vlan_enabled, uint8_t ipv4,
+		uint8_t toggle_mac_addr, uint8_t toggle_ip_addr,
+		uint8_t toggle_udp_port)
+{
+	int retval, i;
+	int burst_size_1, burst_size_2, nb_tx_1, nb_tx_2;
+
+	struct rte_mbuf *pkts_burst_1[MAX_PKT_BURST];
+	struct rte_mbuf *pkts_burst_2[MAX_PKT_BURST];
+
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER34);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+	burst_size_1 = 20;
+	burst_size_2 = 10;
+
+	if (burst_size_1 > MAX_PKT_BURST || burst_size_2 > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkts_burst_1, burst_size_1, vlan_enabled, ipv4, 0,
+			0, 0) != burst_size_1)
+		return -1;
+
+	if (generate_test_burst(pkts_burst_2, burst_size_2, vlan_enabled, ipv4,
+			toggle_mac_addr, toggle_ip_addr, toggle_udp_port) != burst_size_2)
+		return -1;
+
+	/* Send burst 1 on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != burst_size_1) {
+		return -1;
+	}
+	/* Send burst 2 on bonded port */
+	nb_tx_2 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_2,
+			burst_size_2);
+	if (nb_tx_2 != burst_size_2) {
+		return -1;
+	}
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(nb_tx_1 + nb_tx_2)) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				(unsigned int)port_stats.opackets, nb_tx_1 + nb_tx_2);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_1) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.opackets, nb_tx_1);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_2) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.opackets, nb_tx_2);
+		return -1;
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != 0) {
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_l34_tx_burst_ipv4_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(0, 1, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_ipv4_toggle_udp_port(void)
+{
+	return balance_l34_tx_burst(0, 1, 0, 0, 1);
+}
+
+static int
+test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(1, 1, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_ipv6_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(0, 0, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(1, 0, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_ipv6_toggle_udp_port(void)
+{
+	return balance_l34_tx_burst(0, 0, 0, 0, 1);
+}
+
+#define TEST_BALANCE_RX_BURST_SLAVE_COUNT (3)
+
+static int
+test_balance_rx_burst(void)
+{
+	struct rte_mbuf *gen_pkt_burst[TEST_BALANCE_RX_BURST_SLAVE_COUNT]
+	                               [MAX_PKT_BURST];
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	int burst_size[TEST_BALANCE_RX_BURST_SLAVE_COUNT] = { 10, 5, 30 };
+	int i, j, nb_rx;
+
+	memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 3, 1)
+			!= 0)
+		return -1;
+
+	/* Generate test bursts of packets to transmit */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size[i], 0, 0, 1, 0, 0)
+				!= burst_size[i])
+			return -1;
+	}
+	/* Add rx data to slaves */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size[i]);
+	}
+
+	/* Call rx burst on bonded device */
+	/* Send burst on bonded port */
+	nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+	if (nb_rx != burst_size[0] + burst_size[1] + burst_size[2]) {
+		printf("balance rx burst failed\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size[0] + burst_size[1] +
+			burst_size[2])) {
+		printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.ipackets,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+
+	/* Verify bonded slave devices rx counts */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.ipackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.ipackets, burst_size[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[2]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[2],
+				(unsigned int)port_stats.ipackets, burst_size[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.ipackets != 0) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[3],
+				(unsigned int)port_stats.ipackets, 0);
+		return -1;
+	}
+
+	/* free mbufs */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (gen_pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(gen_pkt_burst[i][j]);
+				gen_pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_verify_promiscuous_enable_disable(void)
+{
+	int i, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 4, 1)!= 0)
+		return -1;
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 1) {
+			printf("slave port (%d) promiscuous mode not enabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1);
+
+	/* Initialize bonded device with 2 slaves in active backup mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 2, 1)!= 0)
+		return -1;
+
+	/* Verify that bonded MACs is that of first slave and that the other slave
+	 * MAC hasn't been changed */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	if (rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[1]) != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagated to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of bonded port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of bonded port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_BALANCE_LINK_STATUS_SLAVE_COUNT (4)
+
+static int
+test_balance_verify_slave_link_status_change_behaviour(void)
+{
+	struct rte_mbuf *pkt_burst[TEST_BALANCE_LINK_STATUS_SLAVE_COUNT]
+	                           [MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	const uint8_t *slaves;
+
+	int i, j, burst_size, slave_count;
+
+	memset(pkt_burst, 0, sizeof(pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE,
+			TEST_BALANCE_LINK_STATUS_SLAVE_COUNT, 1)!= 0)
+		return -1;
+
+	if (rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER2)) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of slaves (%d) is not as expected (%d).\n", slave_count,
+				4);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n", slave_count, 4);
+		return -1;
+	}
+
+	/* Set 2 slaves link status to down */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves) != 2) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 2);
+		return -1;
+	}
+
+	/* Send to sets of packet burst and verify that they are balanced across
+	 *  slaves */
+	burst_size = 21;
+
+	if (generate_test_burst(&pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (generate_test_burst(&pkt_burst[1][0], burst_size, 0, 1, 1, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[0][0],
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[1][0],
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->bonded_port_id, (int)port_stats.opackets,
+				burst_size + burst_size);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->slave_port_ids[0], (int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->slave_port_ids[2], (int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	/* verify that all packets get send on primary slave when no other slaves
+	 * are available */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[2], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves) !=
+			1) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 1);
+		return -1;
+	}
+
+	if (generate_test_burst(&pkt_burst[1][0], burst_size, 0, 1, 1, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[1][0],
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size + burst_size +
+			burst_size)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->bonded_port_id, (int)port_stats.opackets,
+				burst_size + burst_size + burst_size);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->slave_port_ids[0], (int)port_stats.opackets,
+				burst_size + burst_size);
+		return -1;
+	}
+
+
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[0], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 1);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[2], 1);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 1);
+
+	for (i = 0; i < TEST_BALANCE_LINK_STATUS_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0) !=
+				burst_size) {
+			return -1;
+		}
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&pkt_burst[i][0], burst_size);
+	}
+
+
+
+	/* Verify that pkts are not received on slaves with link status down */
+
+	rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size * 3)) {
+		printf("(%d) port_stats.ipackets (%d) not as expected (%d)\n",
+				test_params->bonded_port_id, (int)port_stats.ipackets,
+				burst_size * 3);
+		return -1;
+	}
+
+	/* free mbufs allocate for rx testing */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(pkt_burst[i][j]);
+				pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+/** Broadcast Mode Tests */
+
+static int
+test_broadcast_tx_burst(void)
+{
+	int i, pktlen, retval, burst_size, generated_burst_size, nb_tx;
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);
+
+	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+			dst_port_0, 16);
+	pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+			dst_addr_0, pktlen);
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate a burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr,
+			1, test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size) {
+		return -1;
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != burst_size * test_params->bonded_slave_count) {
+		printf("Bonded Port (%d) rx burst failed, packets transmitted value "
+				"(%u) not as expected (%d)\n", test_params->bonded_port_id,
+				nb_tx, burst_size);
+		return -1;
+	}
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size *
+			test_params->bonded_slave_count) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+	}
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (port_stats.opackets != (uint64_t)burst_size) {
+			printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+					test_params->bonded_port_id,
+					(unsigned int)port_stats.opackets, burst_size);
+		}
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != 0) {
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define BROADCAST_RX_BURST_NUM_OF_SLAVES (3)
+
+static int
+test_broadcast_rx_burst(void)
+{
+	struct rte_mbuf *gen_pkt_burst[BROADCAST_RX_BURST_NUM_OF_SLAVES]
+	                               [MAX_PKT_BURST];
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	int burst_size[BROADCAST_RX_BURST_NUM_OF_SLAVES] = { 10, 5, 30 };
+	int i, j, nb_rx;
+
+	memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST, 3, 1)!= 0)
+		return -1;
+
+
+	/* Generate test bursts of packets to transmit */
+	for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size[i], 0, 0, 1, 0,
+				0) != burst_size[i])
+			return -1;
+	}
+
+	/* Add rx data to slave 0 */
+	for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) {
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size[i]);
+	}
+
+
+	/* Call rx burst on bonded device */
+	/* Send burst on bonded port */
+	nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+	if (nb_rx != burst_size[0] + burst_size[1] + burst_size[2]) {
+		printf("round-robin rx burst failed");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size[0] + burst_size[1] +
+			burst_size[2])) {
+		printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.ipackets,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+
+	/* Verify bonded slave devices rx counts */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.ipackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.ipackets, burst_size[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[2]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[2],
+				(unsigned int)port_stats.ipackets,
+				burst_size[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.ipackets != 0) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[3],
+				(unsigned int)port_stats.ipackets, 0);
+		return -1;
+	}
+
+	/* free mbufs allocate for rx testing */
+	for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (gen_pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(gen_pkt_burst[i][j]);
+				gen_pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_broadcast_verify_promiscuous_enable_disable(void)
+{
+	int i, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 4, 1)!= 0)
+		return -1;
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 1) {
+			printf("slave port (%d) promiscuous mode not enabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_broadcast_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;
+
+	int i, retval;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[2], &expected_mac_addr_1);
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST, 4, 1)!= 0)
+		return -1;
+
+	/* Verify that all MACs are the same as first slave added to bonded device */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of primary "
+					"port\n", test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	retval = rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[2]);
+	if (retval != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address has changed to that of primary "
+					"port without stop/start toggle of bonded device\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagated to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary "
+				"port\n", test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_1, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary "
+					"port\n", test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary "
+				"port\n", test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary "
+					"port\n", test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define BROADCAST_LINK_STATUS_NUM_OF_SLAVES (4)
+static int
+test_broadcast_verify_slave_link_status_change_behaviour(void)
+{
+	struct rte_mbuf *pkt_burst[BROADCAST_LINK_STATUS_NUM_OF_SLAVES]
+	                           [MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	const uint8_t *slaves;
+
+	int i, j, burst_size, slave_count;
+
+	memset(pkt_burst, 0, sizeof(pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST,
+			BROADCAST_LINK_STATUS_NUM_OF_SLAVES, 1)!= 0)
+		return -1;
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	/* Set 2 slaves link status to down */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != 2) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 2);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_reset(test_params->slave_port_ids[i]);
+	}
+
+	/* Verify that pkts are not sent on slaves with link status down */
+	burst_size = 21;
+
+	if (generate_test_burst(&pkt_burst[0][0], burst_size, 0, 0, 1, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[0][0],
+			burst_size) != (burst_size * slave_count)) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size * slave_count)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d)\n",
+				test_params->bonded_port_id, (int)port_stats.opackets,
+				burst_size * slave_count);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	for (i = 0; i < BROADCAST_LINK_STATUS_NUM_OF_SLAVES; i++) {
+		if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 0, 1, 0, 0) !=
+				burst_size) {
+			return -1;
+		}
+
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&pkt_burst[i][0], burst_size);
+	}
+
+	/* Verify that pkts are not received on slaves with link status down */
+
+	if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST) !=
+			burst_size + burst_size) {
+		printf("rte_eth_rx_burst\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.ipackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* free mbufs allocate for rx testing */
+	for (i = 0; i < BROADCAST_LINK_STATUS_NUM_OF_SLAVES; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(pkt_burst[i][j]);
+				pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_reconfigure_bonded_device(void)
+{
+	test_params->nb_rx_q = 4;
+	test_params->nb_tx_q = 4;
+
+	if (configure_ethdev(test_params->bonded_port_id, 0)  != 0) {
+		printf("failed to reconfigure bonded device");
+		return -1;
+	}
+
+
+	test_params->nb_rx_q = 2;
+	test_params->nb_tx_q = 2;
+
+	if (configure_ethdev(test_params->bonded_port_id, 0)  != 0) {
+		printf("failed to reconfigure bonded device with less rx/tx queues");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+test_close_bonded_device(void)
+{
+	rte_eth_dev_close(test_params->bonded_port_id);
+	return 0;
+}
+
+static int
+testsuite_teardown(void)
+{
+	if (test_params->pkt_eth_hdr != NULL) {
+		free(test_params->pkt_eth_hdr);
+	}
+
+	return 0;
+}
+
+struct unittest {
+	int (*test_function)(void);
+	const char* success_msg;
+	const char* fail_msg;
+};
+
+struct unittest_suite {
+	int (*setup_function)(void);
+	int (*teardown_function)(void);
+	struct unittest unittests[];
+};
+
+static struct unittest_suite link_bonding_test_suite  = {
+	.setup_function = test_setup,
+	.teardown_function = testsuite_teardown,
+	.unittests = {
+		{ test_create_bonded_device, "test_create_bonded_device succeeded",
+			"test_create_bonded_device failed" },
+		{ test_create_bonded_device_with_invalid_params,
+			"test_create_bonded_device_with_invalid_params succeeded",
+			"test_create_bonded_device_with_invalid_params failed" },
+		{ test_add_slave_to_bonded_device,
+			"test_add_slave_to_bonded_device succeeded",
+			"test_add_slave_to_bonded_device failed" },
+		{ test_add_slave_to_invalid_bonded_device,
+			"test_add_slave_to_invalid_bonded_device succeeded",
+			"test_add_slave_to_invalid_bonded_device failed" },
+		{ test_remove_slave_from_bonded_device,
+			"test_remove_slave_from_bonded_device succeeded ",
+			"test_remove_slave_from_bonded_device failed" },
+		{ test_remove_slave_from_invalid_bonded_device,
+			"test_remove_slave_from_invalid_bonded_device succeeded",
+			"test_remove_slave_from_invalid_bonded_device failed" },
+		{ test_get_slaves_from_bonded_device,
+			"test_get_slaves_from_bonded_device succeeded",
+			"test_get_slaves_from_bonded_device failed" },
+		{ test_add_already_bonded_slave_to_bonded_device,
+			"test_add_already_bonded_slave_to_bonded_device succeeded",
+			"test_add_already_bonded_slave_to_bonded_device failed" },
+		{ test_add_remove_multiple_slaves_to_from_bonded_device,
+			"test_add_remove_multiple_slaves_to_from_bonded_device succeeded",
+			"test_add_remove_multiple_slaves_to_from_bonded_device failed" },
+		{ test_start_bonded_device,
+			"test_start_bonded_device succeeded",
+			"test_start_bonded_device failed" },
+		{ test_stop_bonded_device,
+			"test_stop_bonded_device succeeded",
+			"test_stop_bonded_device failed" },
+		{ test_set_bonding_mode,
+			"test_set_bonding_mode succeeded",
+			"test_set_bonding_mode failed" },
+		{ test_set_primary_slave,
+			"test_set_primary_slave succeeded",
+			"test_set_primary_slave failed" },
+		{ test_set_explicit_bonded_mac,
+			"test_set_explicit_bonded_mac succeeded",
+			"test_set_explicit_bonded_mac failed" },
+		{ test_adding_slave_after_bonded_device_started,
+			"test_adding_slave_after_bonded_device_started succeeded",
+			"test_adding_slave_after_bonded_device_started failed" },
+		{ test_roundrobin_tx_burst,
+			"test_roundrobin_tx_burst succeeded",
+			"test_roundrobin_tx_burst failed" },
+		{ test_roundrobin_rx_burst_on_single_slave,
+			"test_roundrobin_rx_burst_on_single_slave succeeded",
+			"test_roundrobin_rx_burst_on_single_slave failed" },
+		{ test_roundrobin_rx_burst_on_multiple_slaves,
+			"test_roundrobin_rx_burst_on_multiple_slaves succeeded",
+			"test_roundrobin_rx_burst_on_multiple_slaves failed" },
+		{ test_roundrobin_verify_promiscuous_enable_disable,
+			"test_roundrobin_verify_promiscuous_enable_disable succeeded",
+			"test_roundrobin_verify_promiscuous_enable_disable failed" },
+		{ test_roundrobin_verify_mac_assignment,
+			"test_roundrobin_verify_mac_assignment succeeded",
+			"test_roundrobin_verify_mac_assignment failed" },
+		{ test_roundrobin_verify_slave_link_status_change_behaviour,
+			"test_roundrobin_verify_slave_link_status_change_behaviour "
+				"succeeded",
+			"test_roundrobin_verify_slave_link_status_change_behaviour failed" },
+		{ test_activebackup_tx_burst,
+			"test_activebackup_tx_burst succeeded",
+			"test_activebackup_tx_burst failed" },
+		{ test_activebackup_rx_burst,
+			"test_activebackup_rx_burst succeeded",
+			"test_activebackup_rx_burst failed" },
+		{ test_activebackup_verify_promiscuous_enable_disable,
+			"test_activebackup_verify_promiscuous_enable_disable succeeded",
+			"test_activebackup_verify_promiscuous_enable_disable failed" },
+		{ test_activebackup_verify_mac_assignment,
+			"test_activebackup_verify_mac_assignment succeeded",
+			"test_activebackup_verify_mac_assignment failed" },
+		{ test_activebackup_verify_slave_link_status_change_failover,
+			"test_activebackup_verify_slave_link_status_change_failover "
+				"succeeded",
+			"test_activebackup_verify_slave_link_status_change_failover "
+			"failed" },
+		{ test_balance_xmit_policy_configuration,
+			"test_balance_xmit_policy_configuration succeeded",
+			"test_balance_xmit_policy_configuration failed" },
+		{ test_balance_l2_tx_burst,
+			"test_balance_l2_tx_burst succeeded",
+			"test_balance_l2_tx_burst failed" },
+		{ test_balance_l23_tx_burst_ipv4_toggle_ip_addr,
+			"test_balance_l23_tx_burst_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr,
+			"test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_ipv6_toggle_ip_addr,
+			"test_balance_l23_tx_burst_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr,
+			"test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_toggle_mac_addr,
+			"test_balance_l23_tx_burst_toggle_mac_addr succeeded",
+			"test_balance_l23_tx_burst_toggle_mac_addr failed" },
+		{ test_balance_l34_tx_burst_ipv4_toggle_ip_addr,
+			"test_balance_l34_tx_burst_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_ipv4_toggle_udp_port,
+			"test_balance_l34_tx_burst_ipv4_toggle_udp_port succeeded",
+			"test_balance_l34_tx_burst_ipv4_toggle_udp_port failed" },
+		{ test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr,
+			"test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_ipv6_toggle_ip_addr,
+			"test_balance_l34_tx_burst_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr,
+			"test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_ipv6_toggle_udp_port,
+			"test_balance_l34_tx_burst_ipv6_toggle_udp_port succeeded",
+			"test_balance_l34_tx_burst_ipv6_toggle_udp_port failed" },
+		{ test_balance_rx_burst,
+			"test_balance_rx_burst succeeded",
+			"test_balance_rx_burst failed" },
+		{ test_balance_verify_promiscuous_enable_disable,
+			"test_balance_verify_promiscuous_enable_disable succeeded",
+			"test_balance_verify_promiscuous_enable_disable failed" },
+		{ test_balance_verify_mac_assignment,
+			"test_balance_verify_mac_assignment succeeded",
+			"test_balance_verify_mac_assignment failed" },
+		{ test_balance_verify_slave_link_status_change_behaviour,
+			"test_balance_verify_slave_link_status_change_behaviour succeeded",
+			"test_balance_verify_slave_link_status_change_behaviour failed" },
+		{ test_broadcast_tx_burst,
+			"test_broadcast_tx_burst succeeded",
+			"test_broadcast_tx_burst failed" },
+		{ test_broadcast_rx_burst,
+			"test_broadcast_rx_burst succeeded",
+			"test_broadcast_rx_burst failed" },
+		{ test_broadcast_verify_promiscuous_enable_disable,
+			"test_broadcast_verify_promiscuous_enable_disable succeeded",
+			"test_broadcast_verify_promiscuous_enable_disable failed" },
+		{ test_broadcast_verify_mac_assignment,
+			"test_broadcast_verify_mac_assignment succeeded",
+			"test_broadcast_verify_mac_assignment failed" },
+		{ test_broadcast_verify_slave_link_status_change_behaviour,
+			"test_broadcast_verify_slave_link_status_change_behaviour succeeded",
+			"test_broadcast_verify_slave_link_status_change_behaviour failed" },
+		{ test_reconfigure_bonded_device,
+			"test_reconfigure_bonded_device succeeded",
+			"test_reconfigure_bonded_device failed" },
+		{ test_close_bonded_device,
+			"test_close_bonded_device succeeded",
+			"test_close_bonded_device failed" },
+
+		{ NULL , NULL, NULL } /**< NULL terminate unit test array */
+	}
+};
+
+
+int
+test_link_bonding(void)
+{
+	int i = 0;
+
+	if (link_bonding_test_suite.setup_function) {
+		if (link_bonding_test_suite.setup_function() != 0) {
+			return -1;
+		}
+	}
+
+	while (link_bonding_test_suite.unittests[i].test_function) {
+		if (link_bonding_test_suite.unittests[i].test_function() == 0) {
+			printf("%s", link_bonding_test_suite.unittests[i].success_msg ?
+					link_bonding_test_suite.unittests[i].success_msg :
+					"unit test succeeded");
+		}
+		else {
+			printf("%s", link_bonding_test_suite.unittests[i].fail_msg ?
+					link_bonding_test_suite.unittests[i].fail_msg :
+					"unit test failed");
+			return -1;
+		}
+		printf("\n");
+		i++;
+	}
+
+	if (link_bonding_test_suite.teardown_function) {
+		if (link_bonding_test_suite.teardown_function() != 0) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
new file mode 100644
index 0000000..9dcaf44
--- /dev/null
+++ b/app/test/virtual_pmd.c
@@ -0,0 +1,580 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_memory.h>
+
+#include "virtual_pmd.h"
+
+#define MAX_PKT_BURST 512
+
+static const char *virtual_ethdev_driver_name = "Virtual PMD";
+
+struct virtual_ethdev_private {
+	struct rte_eth_stats eth_stats;
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST];
+	int rx_pkt_burst_len;
+};
+
+struct virtual_ethdev_queue {
+	int port_id;
+	int queue_id;
+};
+
+static int
+virtual_ethdev_start_success(struct rte_eth_dev *eth_dev __rte_unused)
+{
+	eth_dev->data->dev_started = 1;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev __rte_unused)
+{
+	eth_dev->data->dev_started = 0;
+
+	return -1;
+}
+static void  virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused)
+{
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_started = 0;
+}
+
+static void
+virtual_ethdev_close(struct rte_eth_dev *dev __rte_unused)
+{}
+
+static int
+virtual_ethdev_configure_success(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static int
+virtual_ethdev_configure_fail(struct rte_eth_dev *dev __rte_unused)
+{
+	return -1;
+}
+
+static void
+virtual_ethdev_info_get(struct rte_eth_dev *dev __rte_unused,
+			 	 	 	 	 	 struct rte_eth_dev_info *dev_info)
+{
+	dev_info->driver_name = virtual_ethdev_driver_name;
+	dev_info->max_mac_addrs = 1;
+
+	dev_info->max_rx_pktlen = (uint32_t)2048;
+
+	dev_info->max_rx_queues = (uint16_t)128;
+	dev_info->max_tx_queues = (uint16_t)512;
+
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static int
+virtual_ethdev_rx_queue_setup_success(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id, uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	struct virtual_ethdev_queue *rx_q;
+
+	rx_q = (struct virtual_ethdev_queue*)
+			rte_zmalloc_socket(NULL, sizeof(struct virtual_ethdev_queue),
+					0, socket_id);
+
+	if (rx_q == NULL)
+		return -1;
+
+	rx_q->port_id = dev->data->port_id;
+	rx_q->queue_id = rx_queue_id;
+
+	dev->data->rx_queues[rx_queue_id] = rx_q;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_rx_queue_setup_fail(struct rte_eth_dev *dev __rte_unused,
+		uint16_t rx_queue_id __rte_unused, uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	return -1;
+}
+
+static int
+virtual_ethdev_tx_queue_setup_success(struct rte_eth_dev *dev,
+		uint16_t tx_queue_id, uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct virtual_ethdev_queue *tx_q;
+
+	tx_q = (struct virtual_ethdev_queue*)
+			rte_zmalloc_socket(NULL, sizeof(struct virtual_ethdev_queue), 0,
+					socket_id);
+
+	if (tx_q == NULL)
+		return -1;
+
+	tx_q->port_id = dev->data->port_id;
+	tx_q->queue_id = tx_queue_id;
+
+	dev->data->tx_queues[tx_queue_id] = tx_q;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_tx_queue_setup_fail(struct rte_eth_dev *dev __rte_unused,
+		uint16_t tx_queue_id __rte_unused, uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	return -1;
+}
+
+static void
+virtual_ethdev_rx_queue_release(void *q __rte_unused)
+{
+}
+
+static void
+virtual_ethdev_tx_queue_release(void *q __rte_unused)
+{
+}
+
+static int
+virtual_ethdev_link_update_success(struct rte_eth_dev *bonded_eth_dev,
+		int wait_to_complete __rte_unused)
+{
+	if (!bonded_eth_dev->data->dev_started) {
+		bonded_eth_dev->data->dev_link.link_status = 0;
+	}
+
+	return 0;
+}
+
+static int
+virtual_ethdev_link_update_fail(struct rte_eth_dev *bonded_eth_dev __rte_unused,
+		int wait_to_complete __rte_unused)
+{
+	return -1;
+}
+
+static void
+virtual_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct virtual_ethdev_private *dev_private = dev->data->dev_private;
+
+	if(stats)
+		rte_memcpy(stats, &dev_private->eth_stats, sizeof(*stats));
+}
+
+static void
+virtual_ethdev_stats_reset(struct rte_eth_dev *dev)
+{
+	struct virtual_ethdev_private *dev_private = dev->data->dev_private;
+
+	dev_private->rx_pkt_burst_len = 0;
+
+	/* Reset internal statistics */
+	memset(&dev_private->eth_stats, 0, sizeof(dev_private->eth_stats));
+}
+
+static void
+virtual_ethdev_promiscuous_mode_enable(struct rte_eth_dev *dev __rte_unused)
+{}
+
+static void
+virtual_ethdev_promiscuous_mode_disable(struct rte_eth_dev *dev __rte_unused)
+{}
+
+
+static struct eth_dev_ops virtual_ethdev_default_dev_ops = {
+		.dev_configure = virtual_ethdev_configure_success,
+		.dev_start = virtual_ethdev_start_success,
+		.dev_stop = virtual_ethdev_stop,
+		.dev_close = virtual_ethdev_close,
+		.dev_infos_get = virtual_ethdev_info_get,
+		.rx_queue_setup = virtual_ethdev_rx_queue_setup_success,
+		.tx_queue_setup = virtual_ethdev_tx_queue_setup_success,
+		.rx_queue_release = virtual_ethdev_rx_queue_release,
+		.tx_queue_release = virtual_ethdev_tx_queue_release,
+		.link_update = virtual_ethdev_link_update_success,
+		.stats_get = virtual_ethdev_stats_get,
+		.stats_reset = virtual_ethdev_stats_reset,
+		.promiscuous_enable = virtual_ethdev_promiscuous_mode_enable,
+		.promiscuous_disable = virtual_ethdev_promiscuous_mode_disable
+};
+
+
+void
+virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->dev_start = virtual_ethdev_start_success;
+	else
+		vrtl_eth_dev->dev_ops->dev_start = virtual_ethdev_start_fail;
+
+}
+
+void
+virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->dev_configure = virtual_ethdev_configure_success;
+	else
+		vrtl_eth_dev->dev_ops->dev_configure = virtual_ethdev_configure_fail;
+}
+
+void
+virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->rx_queue_setup =
+				virtual_ethdev_rx_queue_setup_success;
+	else
+		vrtl_eth_dev->dev_ops->rx_queue_setup =
+				virtual_ethdev_rx_queue_setup_fail;
+}
+
+void
+virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->tx_queue_setup =
+				virtual_ethdev_tx_queue_setup_success;
+	else
+		vrtl_eth_dev->dev_ops->tx_queue_setup =
+				virtual_ethdev_tx_queue_setup_fail;
+}
+
+void
+virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->link_update = virtual_ethdev_link_update_success;
+	else
+		vrtl_eth_dev->dev_ops->link_update = virtual_ethdev_link_update_fail;
+}
+
+
+static uint16_t
+virtual_ethdev_rx_burst_success(void *queue __rte_unused,
+							 struct rte_mbuf **bufs,
+							 uint16_t nb_pkts)
+{
+	struct rte_eth_dev *vrtl_eth_dev;
+	struct virtual_ethdev_queue *pq_map;
+	struct virtual_ethdev_private *dev_private;
+
+	int i;
+
+	pq_map = (struct virtual_ethdev_queue*)queue;
+
+	vrtl_eth_dev = &rte_eth_devices[pq_map->port_id];
+
+	dev_private = vrtl_eth_dev->data->dev_private;
+
+	if (dev_private->rx_pkt_burst_len > 0) {
+		if (dev_private->rx_pkt_burst_len < nb_pkts) {
+
+			for (i = 0; i < dev_private->rx_pkt_burst_len; i++) {
+				bufs[i] = dev_private->rx_pkt_burst[i];
+				dev_private->rx_pkt_burst[i] = NULL;
+			}
+
+			dev_private->eth_stats.ipackets = dev_private->rx_pkt_burst_len;
+		}
+		/* reset private burst values */
+		dev_private->rx_pkt_burst_len = 0;
+	}
+
+	return dev_private->eth_stats.ipackets;
+}
+
+static uint16_t
+virtual_ethdev_rx_burst_fail(void *queue __rte_unused,
+							 struct rte_mbuf **bufs __rte_unused,
+							 uint16_t nb_pkts __rte_unused)
+{
+	return 0;
+}
+
+static uint16_t
+virtual_ethdev_tx_burst_success(void *queue,
+							 struct rte_mbuf **bufs __rte_unused,
+							 uint16_t nb_pkts)
+{
+	struct rte_eth_dev *vrtl_eth_dev;
+	struct virtual_ethdev_queue *tx_q;
+	struct virtual_ethdev_private *dev_private;
+	int i;
+
+	tx_q = (struct virtual_ethdev_queue*)queue;
+
+	vrtl_eth_dev = &rte_eth_devices[tx_q->port_id];
+
+	if (vrtl_eth_dev->data->dev_link.link_status) {
+		dev_private = vrtl_eth_dev->data->dev_private;
+		dev_private->eth_stats.opackets += nb_pkts;
+
+		return nb_pkts;
+	}
+
+	/* free packets in burst */
+	for (i = 0; i < nb_pkts; i++) {
+		if(bufs[i] != NULL)
+			rte_pktmbuf_free(bufs[i]);
+
+		bufs[i] = NULL;
+	}
+
+	return 0;
+}
+
+
+static uint16_t
+virtual_ethdev_tx_burst_fail(void *queue __rte_unused,
+						  struct rte_mbuf **bufs __rte_unused,
+						  uint16_t nb_pkts __rte_unused)
+{
+	return 0;
+}
+
+
+
+void
+virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_success;
+	else
+		vrtl_eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_fail;
+}
+
+
+void
+virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_success;
+	else
+		vrtl_eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_fail;
+}
+
+
+void
+virtual_ethdev_simulate_link_status_interrupt(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;
+
+	_rte_eth_dev_callback_process(vrtl_eth_dev, RTE_ETH_EVENT_INTR_LSC);
+}
+
+
+
+void
+virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id,
+		struct rte_mbuf **pkt_burst, int burst_length)
+{
+	struct virtual_ethdev_private *dev_private = NULL;
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	int i;
+
+	dev_private = vrtl_eth_dev->data->dev_private;
+
+	for (i = 0; i < burst_length; i++) {
+		dev_private->rx_pkt_burst[i] = pkt_burst[i];
+	}
+
+	dev_private->rx_pkt_burst_len = burst_length;
+}
+
+static uint8_t
+get_number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg * ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; i < RTE_MAX_MEMSEG && ms[i].addr != NULL; i++) {
+	   if (sockets < ms[i].socket_id)
+	       sockets = ms[i].socket_id;
+	}
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+}
+
+
+int
+virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
+		uint8_t socket_id)
+{
+	struct rte_pci_device *pci_dev = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct eth_driver *eth_drv = NULL;
+	struct rte_pci_driver *pci_drv = NULL;
+	struct eth_dev_ops *dev_ops = NULL;
+	struct rte_pci_id *id_table = NULL;
+	struct virtual_ethdev_private *dev_private = NULL;
+
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (dev_private) data
+	 */
+
+	if (socket_id >= get_number_of_sockets())
+		goto err;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, socket_id);
+	if (pci_dev == NULL)
+		goto err;
+
+	eth_drv = rte_zmalloc_socket(name, sizeof(*eth_drv), 0, socket_id);
+	if (eth_drv == NULL)
+		goto err;
+
+	pci_drv = rte_zmalloc_socket(name, sizeof(*pci_drv), 0, socket_id);
+	if (pci_drv == NULL)
+		goto err;
+
+	dev_ops = rte_zmalloc_socket(name, sizeof(*dev_ops), 0, socket_id);
+	if (dev_ops == NULL)
+		goto err;
+
+	id_table = rte_zmalloc_socket(name, sizeof(*id_table), 0, socket_id);
+	if (id_table == NULL)
+		goto err;
+
+	dev_private = rte_zmalloc_socket(name, sizeof(*dev_private), 0, socket_id);
+	if (dev_private == NULL)
+		goto err;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate();
+	if (eth_dev == NULL)
+		goto err;
+
+	pci_dev->numa_node = socket_id;
+	pci_drv->name = virtual_ethdev_driver_name;
+	pci_drv->id_table = id_table;
+
+	eth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);
+	eth_dev->driver = eth_drv;
+
+	eth_dev->data->nb_rx_queues = (uint16_t)1;
+	eth_dev->data->nb_tx_queues = (uint16_t)1;
+
+	TAILQ_INIT(&(eth_dev->callbacks));
+
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_link.link_speed = ETH_LINK_SPEED_10000;
+	eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX;
+
+	eth_dev->data->mac_addrs = rte_zmalloc(name, ETHER_ADDR_LEN, 0);
+	if (eth_dev->data->mac_addrs == NULL)
+		goto err;
+
+	memcpy(eth_dev->data->mac_addrs, mac_addr,
+			sizeof(*eth_dev->data->mac_addrs));
+	eth_dev->data->mac_addrs->addr_bytes[5] = eth_dev->data->port_id;
+
+	eth_dev->data->dev_started = 0;
+	eth_dev->data->promiscuous = 0;
+	eth_dev->data->scattered_rx = 0;
+	eth_dev->data->all_multicast = 0;
+
+	memset(dev_private, 0, sizeof(*dev_private));
+	eth_dev->data->dev_private = dev_private;
+
+	eth_dev->dev_ops = dev_ops;
+
+	/* Copy default device operation functions */
+	memcpy(eth_dev->dev_ops, &virtual_ethdev_default_dev_ops,
+			sizeof(*eth_dev->dev_ops));
+
+	eth_dev->pci_dev = pci_dev;
+	eth_dev->pci_dev->driver = &eth_drv->pci_drv;
+
+	eth_dev->pci_dev->driver->id_table->device_id = 0xBEEF;
+
+	eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_success;
+	eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_success;
+
+	return eth_dev->data->port_id;
+
+err:
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (pci_drv)
+		rte_free(pci_drv);
+	if (eth_drv)
+		rte_free(eth_drv);
+	if (dev_ops)
+		rte_free(dev_ops);
+	if (id_table)
+		rte_free(id_table);
+	if (dev_private)
+		rte_free(dev_private);
+
+	return -1;
+}
diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h
new file mode 100644
index 0000000..766b6ac
--- /dev/null
+++ b/app/test/virtual_pmd.h
@@ -0,0 +1,74 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VIRTUAL_ETHDEV_H_
+#define __VIRTUAL_ETHDEV_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ether.h>
+
+int virtual_ethdev_init(void);
+
+int virtual_ethdev_create(const char *name, struct ether_addr *mac_addr, uint8_t socket_id);
+
+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);
+
+void virtual_ethdev_stop_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_rx_queue_setup_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_link_update_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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VIRTUAL_ETHDEV_H_ */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH 3/4] Link bonding integration into testpmd
  2014-05-28 15:32 [dpdk-dev] [PATCH 0/4] Link Bonding Library declan.doherty
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 1/4] " declan.doherty
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 2/4] Link bonding unit tests declan.doherty
@ 2014-05-28 15:32 ` declan.doherty
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 4/4] Add Link Bonding Library to Doxygen declan.doherty
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 127+ messages in thread
From: declan.doherty @ 2014-05-28 15:32 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

  Adding link bonding support to testpmd.
    - Includes the ability to create new bonded devices.
    - Add /remove bonding slave devices.
    - Interogate bonded device stats/configuration
    - Change bonding modes and select balance transmit polices

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 app/test-pmd/cmdline.c    | 550 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/parameters.c |   4 +-
 app/test-pmd/testpmd.c    |  28 ++-
 app/test-pmd/testpmd.h    |   2 +
 4 files changed, 582 insertions(+), 2 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 0be28f6..7c7c9f3 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -84,6 +84,9 @@
 #include <cmdline_socket.h>
 #include <cmdline.h>
 #include <rte_pci_dev_ids.h>
+#ifdef RTE_LIBRTE_BOND
+#include <rte_bond.h>
+#endif
 
 #include "testpmd.h"
 
@@ -393,6 +396,31 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"   Show the bypass configuration for a bypass enabled NIC"
 			" using the lowest port on the NIC.\n\n"
 #endif
+#ifdef RTE_LIBRTE_BOND
+			"create bonded device (mode) (socket)\n"
+			"	Create a new bonded device with specific bonding mode and socket.\n\n"
+
+			"add bonding slave (slave_id) (port_id)\n"
+			"	Add a slave device to a bonded device.\n\n"
+
+			"remove bonding slave (slave_id) (port_id)\n"
+			"	Remove a slave device from a bonded device.\n\n"
+
+			"set bonding mode (value) (port_id)\n"
+			"	Set the bonding mode on a bonded device.\n\n"
+
+			"set bonding primary (slave_id) (port_id)\n"
+			"	Set the primary slave for a bonded device.\n\n"
+
+			"show bonding config (port_id)\n"
+			"	Show the bonding config for port_id.\n\n"
+
+			"set bonding mac_addr (port_id) (address)\n"
+			"	Set the MAC address of a bonded device.\n\n"
+
+			"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"
+#endif
 
 			, list_pkt_forwarding_modes()
 		);
@@ -2849,6 +2877,518 @@ cmdline_parse_inst_t cmd_show_bypass_config = {
 };
 #endif
 
+#ifdef RTE_LIBRTE_BOND
+/* *** SET BONDING MODE *** */
+struct cmd_set_bonding_mode_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t mode;
+	uint8_t value;
+	uint8_t port_id;
+};
+
+static void cmd_set_bonding_mode_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_set_bonding_mode_result *res = parsed_result;
+	portid_t port_id = res->port_id;
+
+	/* Set the bonding mode for the relevant port. */
+	if (0 != rte_eth_bond_mode_set(port_id, res->value)) {
+		printf("\t Failed to set bonding mode for port = %d.\n", port_id);
+	}
+}
+
+cmdline_parse_token_string_t cmd_setbonding_mode_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_mode_result,
+		set, "set");
+cmdline_parse_token_string_t cmd_setbonding_mode_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_mode_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_mode_mode =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_mode_result,
+		mode, "mode");
+cmdline_parse_token_num_t cmd_setbonding_mode_value =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_mode_result,
+		value, UINT8);
+cmdline_parse_token_num_t cmd_setbonding_mode_port =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_mode_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_set_bonding_mode = { .f = cmd_set_bonding_mode_parsed,
+		.help_str = "set bonding mode (mode_value) (port_id): "
+				"Set the bonding mode for port_id", .data = NULL, .tokens = {
+				(void *) &cmd_setbonding_mode_set,
+				(void *) &cmd_setbonding_mode_bonding,
+				(void *) &cmd_setbonding_mode_mode,
+				(void *) &cmd_setbonding_mode_value,
+				(void *) &cmd_setbonding_mode_port,
+				NULL, }, };
+
+/* *** SET BALANCE XMIT POLICY *** */
+struct cmd_set_bonding_balance_xmit_policy_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t balance_xmit_policy;
+	uint8_t port_id;
+	cmdline_fixed_string_t policy;
+};
+
+static void cmd_set_bonding_balance_xmit_policy_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_set_bonding_balance_xmit_policy_result *res = parsed_result;
+	portid_t port_id = res->port_id;
+	uint8_t policy;
+
+	if (!strcmp(res->policy, "l2")) {
+		policy = BALANCE_XMIT_POLICY_LAYER2;
+	} else if (!strcmp(res->policy, "l23")) {
+		policy = BALANCE_XMIT_POLICY_LAYER23;
+	} else if (!strcmp(res->policy, "l34")) {
+		policy = BALANCE_XMIT_POLICY_LAYER34;
+	} else {
+		printf("\t Invalid xmit policy selection");
+		return;
+	}
+
+	/* Set the bonding mode for the relevant port. */
+	if (0 != rte_eth_bond_xmit_policy_set(port_id, policy)) {
+		printf("\t Failed to set bonding balance xmit policy for port = %d.\n",
+				port_id);
+	}
+}
+
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		set, "set");
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_balance_xmit_policy =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		balance_xmit_policy, "balance_xmit_policy");
+cmdline_parse_token_num_t cmd_setbonding_balance_xmit_policy_port =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_policy =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		policy, "l2#l23#l34");
+
+cmdline_parse_inst_t cmd_set_balance_xmit_policy =
+		{ .f = cmd_set_bonding_balance_xmit_policy_parsed, .help_str =
+				"set bonding balance_xmit_policy (port_id) (policy_value): "
+						"Set the bonding balance_xmit_policy for port_id",
+				.data = NULL,
+				.tokens =
+						{ (void *) &cmd_setbonding_balance_xmit_policy_set,
+								(void *) &cmd_setbonding_balance_xmit_policy_bonding,
+								(void *) &cmd_setbonding_balance_xmit_policy_balance_xmit_policy,
+								(void *) &cmd_setbonding_balance_xmit_policy_port,
+								(void *) &cmd_setbonding_balance_xmit_policy_policy,
+								NULL, }, };
+
+/* *** SHOW NIC BONDING CONFIGURATION *** */
+struct cmd_show_bonding_config_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t config;
+	uint8_t port_id;
+};
+
+static void cmd_show_bonding_config_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_show_bonding_config_result *res = parsed_result;
+	int bonding_mode;
+	const uint8_t *slaves;
+	int num_slaves, num_active_slaves;
+	int primary_id;
+	int i;
+	portid_t port_id = res->port_id;
+
+	/* Display the bonding mode.*/
+	bonding_mode = rte_eth_bond_mode_get(port_id);
+	if (bonding_mode < 0) {
+		printf("\tFailed to get bonding mode for port = %d\n", port_id);
+		return;
+	} else
+		printf("\tBonding mode: %d\n", bonding_mode);
+
+	if (bonding_mode == BONDING_MODE_BALANCE) {
+		int balance_xmit_policy;
+
+		balance_xmit_policy = rte_eth_bond_xmit_policy_get(port_id);
+		if (balance_xmit_policy < 0) {
+			printf("\tFailed to get balance xmit policy for port = %d\n",
+					port_id);
+			return;
+		} else {
+			printf("\tBalance Xmit Policy: ");
+
+			switch (balance_xmit_policy) {
+			case BALANCE_XMIT_POLICY_LAYER2:
+				printf("BALANCE_XMIT_POLICY_LAYER2");
+				break;
+			case BALANCE_XMIT_POLICY_LAYER23:
+				printf("BALANCE_XMIT_POLICY_LAYER23");
+				break;
+			case BALANCE_XMIT_POLICY_LAYER34:
+				printf("BALANCE_XMIT_POLICY_LAYER34");
+				break;
+			}
+			printf("\n");
+		}
+	}
+
+	num_slaves = rte_eth_bond_slaves_get(port_id, &slaves);
+
+	if (num_slaves < 0) {
+		printf("\tFailed to get slave list for port = %d\n", port_id);
+		return;
+	}
+	if (num_slaves > 0) {
+		printf("\tSlaves (%d): [", num_slaves);
+		for (i = 0; i < num_slaves - 1; i++) {
+			printf("%d ", slaves[i]);
+		}
+		printf("%d]\n", slaves[num_slaves - 1]);
+	} else {
+		printf("\tSlaves: []\n");
+
+	}
+
+	num_active_slaves = rte_eth_bond_active_slaves_get(port_id, &slaves);
+
+	if (num_active_slaves < 0) {
+		printf("\tFailed to get active slave list for port = %d\n", port_id);
+		return;
+	}
+	if (num_active_slaves > 0) {
+		printf("\tActive Slaves (%d): [", num_active_slaves);
+		for (i = 0; i < num_active_slaves - 1; i++) {
+			printf("%d ", slaves[i]);
+		}
+		printf("%d]\n", slaves[num_active_slaves - 1]);
+
+	} else {
+		printf("\tActive Slaves: []\n");
+
+	}
+
+	primary_id = rte_eth_bond_primary_get(port_id);
+	if (primary_id < 0) {
+		printf("\tFailed to get primary slave for port = %d\n", port_id);
+		return;
+	} else
+		printf("\tPrimary: [%d]\n", primary_id);
+
+}
+
+cmdline_parse_token_string_t cmd_showbonding_config_show =
+TOKEN_STRING_INITIALIZER(struct cmd_show_bonding_config_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_showbonding_config_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_show_bonding_config_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_showbonding_config_config =
+TOKEN_STRING_INITIALIZER(struct cmd_show_bonding_config_result,
+		config, "config");
+cmdline_parse_token_num_t cmd_showbonding_config_port =
+TOKEN_NUM_INITIALIZER(struct cmd_show_bonding_config_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_show_bonding_config = { .f =
+		cmd_show_bonding_config_parsed, .help_str =
+		"show bonding config (port_id): "
+				"Show the bonding config for port_id", .data = NULL, .tokens = {
+		(void *) &cmd_showbonding_config_show,
+		(void *) &cmd_showbonding_config_bonding,
+		(void *) &cmd_showbonding_config_config,
+		(void *) &cmd_showbonding_config_port,
+		NULL, }, };
+
+/* *** SET BONDING PRIMARY *** */
+struct cmd_set_bonding_primary_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t primary;
+	uint8_t slave_id;
+	uint8_t port_id;
+};
+
+static void cmd_set_bonding_primary_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_set_bonding_primary_result *res = parsed_result;
+	portid_t master_port_id = res->port_id;
+	portid_t slave_port_id = res->slave_id;
+
+	/* Set the primary slave for a bonded device. */
+	if (0 != rte_eth_bond_primary_set(master_port_id, slave_port_id)) {
+		printf("\t Failed to set primary slave for port = %d.\n",
+				master_port_id);
+		return;
+	}
+	init_port_config();
+}
+
+cmdline_parse_token_string_t cmd_setbonding_primary_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_primary_result,
+		set, "set");
+cmdline_parse_token_string_t cmd_setbonding_primary_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_primary_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_primary_primary =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_primary_result,
+		primary, "primary");
+cmdline_parse_token_num_t cmd_setbonding_primary_slave =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_primary_result,
+		slave_id, UINT8);
+cmdline_parse_token_num_t cmd_setbonding_primary_port =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_primary_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_set_bonding_primary = { .f =
+		cmd_set_bonding_primary_parsed, .help_str =
+		"set bonding primary (slave_id) (port_id): "
+				"Set the primary slave for port_id", .data = NULL, .tokens = {
+		(void *) &cmd_setbonding_primary_set,
+		(void *) &cmd_setbonding_primary_bonding,
+		(void *) &cmd_setbonding_primary_primary,
+		(void *) &cmd_setbonding_primary_slave,
+		(void *) &cmd_setbonding_primary_port,
+		NULL, }, };
+
+/* *** ADD SLAVE *** */
+struct cmd_add_bonding_slave_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t slave;
+	uint8_t slave_id;
+	uint8_t port_id;
+};
+
+static void cmd_add_bonding_slave_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_add_bonding_slave_result *res = parsed_result;
+	portid_t master_port_id = res->port_id;
+	portid_t slave_port_id = res->slave_id;
+
+	/* Set the primary slave for a bonded device. */
+	if (0 != rte_eth_bond_slave_add(master_port_id, slave_port_id)) {
+		printf("\t Failed to add slave %d to master port = %d.\n",
+				slave_port_id, master_port_id);
+		return;
+	}
+	init_port_config();
+}
+
+cmdline_parse_token_string_t cmd_addbonding_slave_add =
+TOKEN_STRING_INITIALIZER(struct cmd_add_bonding_slave_result,
+		add, "add");
+cmdline_parse_token_string_t cmd_addbonding_slave_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_add_bonding_slave_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_addbonding_slave_slave =
+TOKEN_STRING_INITIALIZER(struct cmd_add_bonding_slave_result,
+		slave, "slave");
+cmdline_parse_token_num_t cmd_addbonding_slave_slaveid =
+TOKEN_NUM_INITIALIZER(struct cmd_add_bonding_slave_result,
+		slave_id, UINT8);
+cmdline_parse_token_num_t cmd_addbonding_slave_port =
+TOKEN_NUM_INITIALIZER(struct cmd_add_bonding_slave_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_add_bonding_slave = {
+		.f = cmd_add_bonding_slave_parsed, .help_str =
+				"add bonding slave (slave_id) (port_id): "
+						"Add a slave device to a bonded device", .data = NULL,
+		.tokens = { (void *) &cmd_addbonding_slave_add,
+				(void *) &cmd_addbonding_slave_bonding,
+				(void *) &cmd_addbonding_slave_slave,
+				(void *) &cmd_addbonding_slave_slaveid,
+				(void *) &cmd_addbonding_slave_port,
+				NULL, }, };
+
+/* *** REMOVE SLAVE *** */
+struct cmd_remove_bonding_slave_result {
+	cmdline_fixed_string_t remove;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t slave;
+	uint8_t slave_id;
+	uint8_t port_id;
+};
+
+static void cmd_remove_bonding_slave_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_remove_bonding_slave_result *res = parsed_result;
+	portid_t master_port_id = res->port_id;
+	portid_t slave_port_id = res->slave_id;
+
+	/* Set the primary slave for a bonded device. */
+	if (0 != rte_eth_bond_slave_remove(master_port_id, slave_port_id)) {
+		printf("\t Failed to remove slave %d from master port = %d.\n",
+				slave_port_id, master_port_id);
+		return;
+	}
+	init_port_config();
+}
+
+cmdline_parse_token_string_t cmd_removebonding_slave_remove =
+TOKEN_STRING_INITIALIZER(struct cmd_remove_bonding_slave_result,
+		remove, "remove");
+cmdline_parse_token_string_t cmd_removebonding_slave_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_remove_bonding_slave_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_removebonding_slave_slave =
+TOKEN_STRING_INITIALIZER(struct cmd_remove_bonding_slave_result,
+		slave, "slave");
+cmdline_parse_token_num_t cmd_removebonding_slave_slaveid =
+TOKEN_NUM_INITIALIZER(struct cmd_remove_bonding_slave_result,
+		slave_id, UINT8);
+cmdline_parse_token_num_t cmd_removebonding_slave_port =
+TOKEN_NUM_INITIALIZER(struct cmd_remove_bonding_slave_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_remove_bonding_slave = { .f =
+		cmd_remove_bonding_slave_parsed, .help_str =
+		"remove bonding slave (slave_id) (port_id): "
+				"Remove a slave device from a bonded device", .data = NULL,
+		.tokens = { (void *) &cmd_removebonding_slave_remove,
+				(void *) &cmd_removebonding_slave_bonding,
+				(void *) &cmd_removebonding_slave_slave,
+				(void *) &cmd_removebonding_slave_slaveid,
+				(void *) &cmd_removebonding_slave_port,
+				NULL, }, };
+
+/* *** CREATE BONDED DEVICE *** */
+struct cmd_create_bonded_device_result {
+	cmdline_fixed_string_t create;
+	cmdline_fixed_string_t bonded;
+	cmdline_fixed_string_t device;
+	uint8_t mode;
+	uint8_t socket;
+};
+
+static void cmd_create_bonded_device_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_create_bonded_device_result *res = parsed_result;
+
+	int port_id;
+	if (test_done == 0) {
+		printf("Please stop forwarding first\n");
+		return;
+	}
+
+	port_id = rte_eth_bond_create("testpmd-bonded-dev", res->mode, res->socket);
+	/* Create a new bonded device. */
+	if (port_id < 0) {
+		printf("\t Failed to create bonded device.\n");
+		return;
+	} else {
+		printf("\t Created new bonded device (port %d).\n", port_id);
+		/* Update number of ports */
+		nb_ports = rte_eth_dev_count();
+		reconfig(port_id);
+		rte_eth_promiscuous_enable(port_id);
+	}
+
+}
+
+cmdline_parse_token_string_t cmd_createbonded_device_create =
+TOKEN_STRING_INITIALIZER(struct cmd_create_bonded_device_result,
+		create, "create");
+cmdline_parse_token_string_t cmd_createbonded_device_bonded =
+TOKEN_STRING_INITIALIZER(struct cmd_create_bonded_device_result,
+		bonded, "bonded");
+cmdline_parse_token_string_t cmd_createbonded_device_device =
+TOKEN_STRING_INITIALIZER(struct cmd_create_bonded_device_result,
+		device, "device");
+cmdline_parse_token_num_t cmd_createbonded_device_mode =
+TOKEN_NUM_INITIALIZER(struct cmd_create_bonded_device_result,
+		mode, UINT8);
+cmdline_parse_token_num_t cmd_createbonded_device_socket =
+TOKEN_NUM_INITIALIZER(struct cmd_create_bonded_device_result,
+		socket, UINT8);
+
+cmdline_parse_inst_t cmd_create_bonded_device =
+		{ .f = cmd_create_bonded_device_parsed,
+				.help_str =
+						"create bonded device (mode) (socket): "
+								"Create a new bonded device with specific bonding mode and socket",
+				.data = NULL, .tokens = {
+						(void *) &cmd_createbonded_device_create,
+						(void *) &cmd_createbonded_device_bonded,
+						(void *) &cmd_createbonded_device_device,
+						(void *) &cmd_createbonded_device_mode,
+						(void *) &cmd_createbonded_device_socket,
+						NULL, }, };
+
+/* *** SET MAC ADDRESS IN BONDED DEVICE *** */
+struct cmd_set_bond_mac_addr_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t mac_addr;
+	uint8_t port_num;
+	struct ether_addr address;
+};
+
+static void cmd_set_bond_mac_addr_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_set_bond_mac_addr_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_mac_address_set(res->port_num, &res->address);
+
+	/* 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_mac_addr_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mac_addr_result, set,
+		"set");
+cmdline_parse_token_string_t cmd_set_bond_mac_addr_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mac_addr_result, bonding,
+		"bonding");
+cmdline_parse_token_string_t cmd_set_bond_mac_addr_mac =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mac_addr_result, mac_addr,
+		"mac_addr");
+cmdline_parse_token_num_t cmd_set_bond_mac_addr_portnum =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bond_mac_addr_result, port_num, UINT8);
+cmdline_parse_token_etheraddr_t cmd_set_bond_mac_addr_addr =
+TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_bond_mac_addr_result, address);
+
+cmdline_parse_inst_t cmd_set_bond_mac_addr = {
+		.f = cmd_set_bond_mac_addr_parsed, .data = (void *) 0, .help_str =
+				"set bonding mac_addr (port_id) (address): ", .tokens = {
+				(void *) &cmd_set_bond_mac_addr_set,
+				(void *) &cmd_set_bond_mac_addr_bonding,
+				(void *) &cmd_set_bond_mac_addr_mac,
+				(void *) &cmd_set_bond_mac_addr_portnum,
+				(void *) &cmd_set_bond_mac_addr_addr,
+				NULL, }, };
+
+#endif /* RTE_LIBRTE_BOND */
+
 /* *** SET FORWARDING MODE *** */
 struct cmd_set_fwd_mode_result {
 	cmdline_fixed_string_t set;
@@ -5333,6 +5873,16 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_set_bypass_timeout,
 	(cmdline_parse_inst_t *)&cmd_show_bypass_config,
 #endif
+#ifdef RTE_LIBRTE_BOND
+	(cmdline_parse_inst_t *) &cmd_set_bonding_mode,
+	(cmdline_parse_inst_t *) &cmd_show_bonding_config,
+	(cmdline_parse_inst_t *) &cmd_set_bonding_primary,
+	(cmdline_parse_inst_t *) &cmd_add_bonding_slave,
+	(cmdline_parse_inst_t *) &cmd_remove_bonding_slave,
+	(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,
+#endif
 	(cmdline_parse_inst_t *)&cmd_vlan_offload,
 	(cmdline_parse_inst_t *)&cmd_vlan_tpid,
 	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter_all,
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 7a60048..6b44ef0 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -75,7 +75,9 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_etheraddr.h>
 #endif
-
+#ifdef RTE_LIBRTE_BOND
+#include <rte_bond.h>
+#endif
 #include "testpmd.h"
 
 static void
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index bc38305..a49b322 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -300,7 +300,7 @@ struct rte_fdir_conf fdir_conf = {
 	.drop_queue = 127,
 };
 
-static volatile int test_done = 1; /* stop packet forwarding when set to 1. */
+volatile int test_done = 1; /* stop packet forwarding when set to 1. */
 
 struct queue_stats_mappings tx_queue_stats_mappings_array[MAX_TX_QUEUE_STATS_MAPPINGS];
 struct queue_stats_mappings rx_queue_stats_mappings_array[MAX_RX_QUEUE_STATS_MAPPINGS];
@@ -625,6 +625,32 @@ init_config(void)
 		rte_exit(EXIT_FAILURE, "FAIL from init_fwd_streams()\n");
 }
 
+
+void
+reconfig(portid_t new_port_id)
+{
+	struct rte_port *port;
+
+	/* Reconfiguration of Ethernet ports. */
+	ports = rte_realloc(ports,
+			    sizeof(struct rte_port) * nb_ports,
+			    CACHE_LINE_SIZE);
+	if (ports == NULL) {
+		rte_exit(EXIT_FAILURE, "rte_realloc(%d struct rte_port) "
+							"failed\n", nb_ports);
+	}
+
+	port = &ports[new_port_id];
+	rte_eth_dev_info_get(new_port_id, &port->dev_info);
+
+	/* set flag to initialize port/queue */
+	port->need_reconfig = 1;
+	port->need_reconfig_queues = 1;
+
+	init_port_config();
+}
+
+
 int
 init_fwd_streams(void)
 {
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 0cf5a92..1f54787 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -279,6 +279,7 @@ extern uint16_t port_topology; /**< set by "--port-topology" parameter */
 extern uint8_t no_flush_rx; /**<set by "--no-flush-rx" parameter */
 extern uint8_t  mp_anon; /**< set by "--mp-anon" parameter */
 extern uint8_t no_link_check; /**<set by "--disable-link-check" parameter */
+extern volatile int test_done; /* stop packet forwarding when set to 1. */
 
 #ifdef RTE_NIC_BYPASS
 extern uint32_t bypass_timeout; /**< Store the NIC bypass watchdog timeout */
@@ -452,6 +453,7 @@ void fwd_config_display(void);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
 void set_def_fwd_config(void);
+void reconfig(portid_t new_port_id);
 int init_fwd_streams(void);
 
 
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH 4/4] Add Link Bonding Library to Doxygen
  2014-05-28 15:32 [dpdk-dev] [PATCH 0/4] Link Bonding Library declan.doherty
                   ` (2 preceding siblings ...)
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 3/4] Link bonding integration into testpmd declan.doherty
@ 2014-05-28 15:32 ` declan.doherty
  2014-05-28 17:49 ` [dpdk-dev] [PATCH 0/4] Link Bonding Library Neil Horman
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 127+ messages in thread
From: declan.doherty @ 2014-05-28 15:32 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 doc/doxy-api-index.md | 1 +
 doc/doxy-api.conf     | 1 +
 2 files changed, 2 insertions(+)

diff --git a/doc/doxy-api-index.md b/doc/doxy-api-index.md
index 2825c08..2206c68 100644
--- a/doc/doxy-api-index.md
+++ b/doc/doxy-api-index.md
@@ -36,6 +36,7 @@ API {#index}
 There are many libraries, so their headers may be grouped by topics:
 
 - **device**:
+  [bond]               (@ref rte_bond.h),
   [ethdev]             (@ref rte_ethdev.h),
   [devargs]            (@ref rte_devargs.h),
   [KNI]                (@ref rte_kni.h),
diff --git a/doc/doxy-api.conf b/doc/doxy-api.conf
index 642f77a..a9c5b30 100644
--- a/doc/doxy-api.conf
+++ b/doc/doxy-api.conf
@@ -30,6 +30,7 @@
 
 PROJECT_NAME            = DPDK
 INPUT                   = doc/doxy-api-index.md \
+                          lib/librte_bond \
                           lib/librte_eal/common/include \
                           lib/librte_ether \
                           lib/librte_hash \
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH 1/4] Link Bonding Library
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 1/4] " declan.doherty
@ 2014-05-28 16:54   ` Shaw, Jeffrey B
  2014-05-29 13:32     ` Doherty, Declan
  0 siblings, 1 reply; 127+ messages in thread
From: Shaw, Jeffrey B @ 2014-05-28 16:54 UTC (permalink / raw)
  To: Doherty, Declan, dev

Hi Declan,
I'm worried about one thing in "bond_ethdev_tx_broadcast()" related to freeing of the broadcasted packets.

> +static uint16_t
> +bond_ethdev_tx_broadcast(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
> +{
> +	struct bond_dev_private *internals;
> +	struct bond_tx_queue *bd_tx_q;
> +
> +	uint8_t num_of_slaves;
> +	uint8_t slaves[RTE_MAX_ETHPORTS];
> +
> +	uint16_t num_tx_total = 0;
> +
> +	int i;
> +
> +	bd_tx_q = (struct bond_tx_queue *)queue;
> +	internals = bd_tx_q->dev_private;
> +
> +	/* Copy slave list to protect against slave up/down changes during tx
> +	 * bursting */
> +	num_of_slaves = internals->active_slave_count;
> +	memcpy(slaves, internals->active_slaves,
> +			sizeof(internals->active_slaves[0]) * num_of_slaves);
> +
> +	if (num_of_slaves < 1)
> +		return 0;
> +
> +
> +	for (i = 0; i < num_of_slaves; i++) {
> +		num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
> +				bufs, nb_pkts);
> +	}
> +
> +	return num_tx_total;
> +}
> +

Transmitting the same buffers on all slaves will cause problems when the PMD frees the mbufs for previously transmitted packets.
So if you broadcast 1 packet on 4 slaves, each of the 4 slaves will (eventually) have to free the same mbuf.  Without updating the refcnt, you will end up incorrectly freeing the same mbuf 3 extra times.

Your test application does not catch this case since the max packets that are tested is 320, which is less than the size of the Tx descriptor rings (512).  Try testing with more packets and you should see some latent segmentation faults.  You should also see this with testpmd, if you try broadcasting enough packets.


Thanks,
Jeff

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
  2014-05-28 15:32 [dpdk-dev] [PATCH 0/4] Link Bonding Library declan.doherty
                   ` (3 preceding siblings ...)
  2014-05-28 15:32 ` [dpdk-dev] [PATCH 4/4] Add Link Bonding Library to Doxygen declan.doherty
@ 2014-05-28 17:49 ` Neil Horman
  2014-05-29 10:33   ` Doherty, Declan
  2014-05-29  3:23 ` Cao, Waterman
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 127+ messages in thread
From: Neil Horman @ 2014-05-28 17:49 UTC (permalink / raw)
  To: declan.doherty; +Cc: dev

On Wed, May 28, 2014 at 04:32:00PM +0100, declan.doherty@intel.com wrote:
> From: Declan Doherty <declan.doherty@intel.com>
> 
> Initial release of Link Bonding Library (lib/librte_bond) with support for 
> bonding modes :
>  0 - Round Robin
>  1 - Active Backup
>  2 - Balance l2 / l23 / l34 
>  3 - Broadcast
> 
Why make this a separate library?  That requires exposure of yet another API to
applications.  Instead, why not write a PMD that can enslave other PMD's and
treat them all as a single interface?  That way this all works with the existing
API.

Neil

> patches split:
>  1 - library + makefile changes
>  2 - Unit test suite, including code to generate packet bursts for
>     testing rx and tx functionality of bonded device and a
>     virtual/stubbed out ethdev for use as slave ethdev in testing
>  3 - Link bonding integration into testpmd, including :
>      - Includes the ability to  create new bonded devices.
>      - Add /remove bonding slave devices. 
>      - Interogate bonded device stats/configuration
>      - Change bonding modes and select balance transmit polices
>  4 - Add Link Bonding Library to Doxygen
> 
> 
>  app/test-pmd/cmdline.c            |  550 +++++
>  app/test-pmd/parameters.c         |    4 +-
>  app/test-pmd/testpmd.c            |   28 +-
>  app/test-pmd/testpmd.h            |    2 +
>  app/test/Makefile                 |    3 +
>  app/test/commands.c               |    3 +
>  app/test/packet_burst_generator.c |  276 +++
>  app/test/packet_burst_generator.h |   85 +
>  app/test/test.h                   |    1 +
>  app/test/test_link_bonding.c      | 4007 +++++++++++++++++++++++++++++++++++++
>  app/test/virtual_pmd.c            |  580 ++++++
>  app/test/virtual_pmd.h            |   74 +
>  config/common_bsdapp              |    5 +
>  config/common_linuxapp            |    5 +
>  doc/doxy-api-index.md             |    1 +
>  doc/doxy-api.conf                 |    1 +
>  lib/Makefile                      |    1 +
>  lib/librte_bond/Makefile          |   28 +
>  lib/librte_bond/rte_bond.c        | 1679 ++++++++++++++++
>  lib/librte_bond/rte_bond.h        |  228 +++
>  mk/rte.app.mk                     |    5 +
>  21 files changed, 7564 insertions(+), 2 deletions(-)
>  create mode 100644 app/test/packet_burst_generator.c
>  create mode 100644 app/test/packet_burst_generator.h
>  create mode 100644 app/test/test_link_bonding.c
>  create mode 100644 app/test/virtual_pmd.c
>  create mode 100644 app/test/virtual_pmd.h
>  create mode 100644 lib/librte_bond/Makefile
>  create mode 100644 lib/librte_bond/rte_bond.c
>  create mode 100644 lib/librte_bond/rte_bond.h
> 
> -- 
> 1.8.5.3
> 
> 

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
  2014-05-28 15:32 [dpdk-dev] [PATCH 0/4] Link Bonding Library declan.doherty
                   ` (4 preceding siblings ...)
  2014-05-28 17:49 ` [dpdk-dev] [PATCH 0/4] Link Bonding Library Neil Horman
@ 2014-05-29  3:23 ` Cao, Waterman
  2014-05-29 10:35   ` Doherty, Declan
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
  2014-06-13 14:41 ` [dpdk-dev] [PATCH v3 0/5] Link Bonding PMD Library Declan Doherty
  7 siblings, 1 reply; 127+ messages in thread
From: Cao, Waterman @ 2014-05-29  3:23 UTC (permalink / raw)
  To: Doherty, Declan, dev, dev

Hi declan,

  Do you send out Patch 1,2, 3 for link bonding?
  Only see patch 0 and 4.

Thanks
Waterman 

-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of declan.doherty@intel.com
Sent: Wednesday, May 28, 2014 11:32 PM
To: dev@dpdk.org; dev@dpdk.org
Subject: [dpdk-dev] [PATCH 0/4] Link Bonding Library

From: Declan Doherty <declan.doherty@intel.com>

Initial release of Link Bonding Library (lib/librte_bond) with support for bonding modes :
 0 - Round Robin
 1 - Active Backup
 2 - Balance l2 / l23 / l34
 3 - Broadcast

patches split:
 1 - library + makefile changes
 2 - Unit test suite, including code to generate packet bursts for
    testing rx and tx functionality of bonded device and a
    virtual/stubbed out ethdev for use as slave ethdev in testing
 3 - Link bonding integration into testpmd, including :
     - Includes the ability to  create new bonded devices.
     - Add /remove bonding slave devices. 
     - Interogate bonded device stats/configuration
     - Change bonding modes and select balance transmit polices
 4 - Add Link Bonding Library to Doxygen


 app/test-pmd/cmdline.c            |  550 +++++
 app/test-pmd/parameters.c         |    4 +-
 app/test-pmd/testpmd.c            |   28 +-
 app/test-pmd/testpmd.h            |    2 +
 app/test/Makefile                 |    3 +
 app/test/commands.c               |    3 +
 app/test/packet_burst_generator.c |  276 +++
 app/test/packet_burst_generator.h |   85 +
 app/test/test.h                   |    1 +
 app/test/test_link_bonding.c      | 4007 +++++++++++++++++++++++++++++++++++++
 app/test/virtual_pmd.c            |  580 ++++++
 app/test/virtual_pmd.h            |   74 +
 config/common_bsdapp              |    5 +
 config/common_linuxapp            |    5 +
 doc/doxy-api-index.md             |    1 +
 doc/doxy-api.conf                 |    1 +
 lib/Makefile                      |    1 +
 lib/librte_bond/Makefile          |   28 +
 lib/librte_bond/rte_bond.c        | 1679 ++++++++++++++++
 lib/librte_bond/rte_bond.h        |  228 +++
 mk/rte.app.mk                     |    5 +
 21 files changed, 7564 insertions(+), 2 deletions(-)  create mode 100644 app/test/packet_burst_generator.c  create mode 100644 app/test/packet_burst_generator.h  create mode 100644 app/test/test_link_bonding.c  create mode 100644 app/test/virtual_pmd.c  create mode 100644 app/test/virtual_pmd.h  create mode 100644 lib/librte_bond/Makefile  create mode 100644 lib/librte_bond/rte_bond.c  create mode 100644 lib/librte_bond/rte_bond.h

--
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
  2014-05-28 17:49 ` [dpdk-dev] [PATCH 0/4] Link Bonding Library Neil Horman
@ 2014-05-29 10:33   ` Doherty, Declan
  2014-05-29 11:33     ` Neil Horman
  0 siblings, 1 reply; 127+ messages in thread
From: Doherty, Declan @ 2014-05-29 10:33 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev

-----Original Message-----
> From: Neil Horman [mailto:nhorman@tuxdriver.com] 
> Sent: Wednesday, May 28, 2014 6:49 PM
> To: Doherty, Declan
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
>
> On Wed, May 28, 2014 at 04:32:00PM +0100, declan.doherty@intel.com wrote:
> > From: Declan Doherty <declan.doherty@intel.com>
> > 
> > Initial release of Link Bonding Library (lib/librte_bond) with support 
> > for bonding modes :
> >  0 - Round Robin
> >  1 - Active Backup
> >  2 - Balance l2 / l23 / l34
> >  3 - Broadcast
> > 
> Why make this a separate library?  That requires exposure of yet another API to applications.  Instead, why > not write a PMD that can enslave other PMD's and treat them all as a single interface?  That way this all >  > works with the existing API.
>
> Neil

Hi Neil,
the link bonding device is essentially a software PMD, and as such supports all the standard PMD APIs, the only new APIs which the link bonding library introduces  are for the control operations of the bonded device which are currently unsupported by the standard PMD API. Operations such as creating, adding/removing slaves, and configuring the modes of operation of the device have no analogous APIs in the current PMD API and required new ones to be created .

Declan
--------------------------------------------------------------
Intel Shannon Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263
Business address: Dromore House, East Park, Shannon, Co. Clare

This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
  2014-05-29  3:23 ` Cao, Waterman
@ 2014-05-29 10:35   ` Doherty, Declan
  0 siblings, 0 replies; 127+ messages in thread
From: Doherty, Declan @ 2014-05-29 10:35 UTC (permalink / raw)
  To: Cao, Waterman, dev, dev

> From: Cao, Waterman 
> Sent: Thursday, May 29, 2014 4:23 AM
> To: Doherty, Declan; dev@dpdk.org; dev@dpdk.org
> Cc: Cao, Waterman
> Subject: RE: [dpdk-dev] [PATCH 0/4] Link Bonding Library
>
> Hi declan,
>
>   Do you send out Patch 1,2, 3 for link bonding?
>   Only see patch 0 and 4.
>
> Thanks
> Waterman 

Hi Waterman, 

As far as I can see all the patches have been submitted, and are visible on the mailing list archives.

Declan
--------------------------------------------------------------
Intel Shannon Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263
Business address: Dromore House, East Park, Shannon, Co. Clare

This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
  2014-05-29 10:33   ` Doherty, Declan
@ 2014-05-29 11:33     ` Neil Horman
  0 siblings, 0 replies; 127+ messages in thread
From: Neil Horman @ 2014-05-29 11:33 UTC (permalink / raw)
  To: Doherty, Declan; +Cc: dev

On Thu, May 29, 2014 at 10:33:00AM +0000, Doherty, Declan wrote:
> -----Original Message-----
> > From: Neil Horman [mailto:nhorman@tuxdriver.com] 
> > Sent: Wednesday, May 28, 2014 6:49 PM
> > To: Doherty, Declan
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
> >
> > On Wed, May 28, 2014 at 04:32:00PM +0100, declan.doherty@intel.com wrote:
> > > From: Declan Doherty <declan.doherty@intel.com>
> > > 
> > > Initial release of Link Bonding Library (lib/librte_bond) with support 
> > > for bonding modes :
> > >  0 - Round Robin
> > >  1 - Active Backup
> > >  2 - Balance l2 / l23 / l34
> > >  3 - Broadcast
> > > 
> > Why make this a separate library?  That requires exposure of yet another API to applications.  Instead, why > not write a PMD that can enslave other PMD's and treat them all as a single interface?  That way this all >  > works with the existing API.
> >
> > Neil
> 
> Hi Neil,
> the link bonding device is essentially a software PMD, and as such supports all the standard PMD APIs, the only new APIs which the link bonding library introduces  are for the control operations of the bonded device which are currently unsupported by the standard PMD API. Operations such as creating, adding/removing slaves, and configuring the modes of operation of the device have no analogous APIs in the current PMD API and required new ones to be created .

Thats really only true in spirit, in the sense that this library transmits and
receives frames like a PMD does.  In practice it doesn't work and isn't
architected the same way.  You don't register the driver using the same method
as the other PMDs, which means that using --vdev on the command line wont work
for this type of device.  It also implies that applications have to be made
specifically aware of the fact that they are using a bonded interface (i.e. they
need to call the bonding setup routines to create the bond).  I would recommend:

1) Register the pmd using the PMD_DRIVER_REGISTER macro, like other PMD's
2) Use the kvargs library to support configuration via the --vdev command line
option, so bonds can be created administratively, rather than just
programatically
3) Separate the command api from the PMD functionality into separate libraries
(use control mbufs to communicate configuration changes to the pmd).  This will
allow users to dynamically load the pmd functionality (without compile or run
time linking requirements), and then optionally use the programatic interface
(or not if they want to save memory)

Regards
Neil

> 
> Declan
> --------------------------------------------------------------
> Intel Shannon Limited
> Registered in Ireland
> Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
> Registered Number: 308263
> Business address: Dromore House, East Park, Shannon, Co. Clare
> 
> This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.
> 
> 
> 

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH 1/4] Link Bonding Library
  2014-05-28 16:54   ` Shaw, Jeffrey B
@ 2014-05-29 13:32     ` Doherty, Declan
  0 siblings, 0 replies; 127+ messages in thread
From: Doherty, Declan @ 2014-05-29 13:32 UTC (permalink / raw)
  To: Shaw, Jeffrey B, dev



> -----Original Message-----
> From: Shaw, Jeffrey B
> Sent: Wednesday, May 28, 2014 5:55 PM
> To: Doherty, Declan; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH 1/4] Link Bonding Library
> 
> Hi Declan,
> I'm worried about one thing in "bond_ethdev_tx_broadcast()" related to
> freeing of the broadcasted packets.
> 
> > +static uint16_t
> > +bond_ethdev_tx_broadcast(void *queue, struct rte_mbuf **bufs,
> > +uint16_t nb_pkts) {
> > +	struct bond_dev_private *internals;
> > +	struct bond_tx_queue *bd_tx_q;
> > +
> > +	uint8_t num_of_slaves;
> > +	uint8_t slaves[RTE_MAX_ETHPORTS];
> > +
> > +	uint16_t num_tx_total = 0;
> > +
> > +	int i;
> > +
> > +	bd_tx_q = (struct bond_tx_queue *)queue;
> > +	internals = bd_tx_q->dev_private;
> > +
> > +	/* Copy slave list to protect against slave up/down changes during tx
> > +	 * bursting */
> > +	num_of_slaves = internals->active_slave_count;
> > +	memcpy(slaves, internals->active_slaves,
> > +			sizeof(internals->active_slaves[0]) * num_of_slaves);
> > +
> > +	if (num_of_slaves < 1)
> > +		return 0;
> > +
> > +
> > +	for (i = 0; i < num_of_slaves; i++) {
> > +		num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q-
> >queue_id,
> > +				bufs, nb_pkts);
> > +	}
> > +
> > +	return num_tx_total;
> > +}
> > +
> 
> Transmitting the same buffers on all slaves will cause problems when the PMD
> frees the mbufs for previously transmitted packets.
> So if you broadcast 1 packet on 4 slaves, each of the 4 slaves will (eventually)
> have to free the same mbuf.  Without updating the refcnt, you will end up
> incorrectly freeing the same mbuf 3 extra times.
> 
> Your test application does not catch this case since the max packets that are
> tested is 320, which is less than the size of the Tx descriptor rings (512).  Try
> testing with more packets and you should see some latent segmentation
> faults.  You should also see this with testpmd, if you try broadcasting enough
> packets.
> 
> 
> Thanks,
> Jeff

Hey Jeff, I'm not sure why I didn't see this in testing using on the test-pmd app, but it's obvious that this will cause issues. I'll add code to increment the refcnt in each mbuf by (num_of_slaves -1) in the bond_ethdev_tx_broadcast() function and also add a unit test to validate this in the next version of the patch.

Thanks,
Declan
--------------------------------------------------------------
Intel Shannon Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263
Business address: Dromore House, East Park, Shannon, Co. Clare

This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-05-28 15:32 [dpdk-dev] [PATCH 0/4] Link Bonding Library declan.doherty
                   ` (5 preceding siblings ...)
  2014-05-29  3:23 ` Cao, Waterman
@ 2014-06-04 15:18 ` declan.doherty
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 1/4] " declan.doherty
                     ` (9 more replies)
  2014-06-13 14:41 ` [dpdk-dev] [PATCH v3 0/5] Link Bonding PMD Library Declan Doherty
  7 siblings, 10 replies; 127+ messages in thread
From: declan.doherty @ 2014-06-04 15:18 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

v2 patch additions,
fix for tx burst broadcast, incrementing the reference count on each mbuf by the number of slaves - 1 
add/remove slave behavior chnange to fix primary slave port assignment 
patchcheck code fixes 

Initial release of Link Bonding Library (lib/librte_bond) with support for bonding modes :
 0 - Round Robin
 1 - Active Backup
 2 - Balance l2 / l23 / l34
 3 - Broadcast

patches split:
 1 - library + makefile changes
 2 - Unit test suite, including code to generate packet bursts for
    testing rx and tx functionality of bonded device and a
    virtual/stubbed out ethdev for use as slave ethdev in testing
 3 - Link bonding integration into testpmd, including :
     - Includes the ability to  create new bonded devices.
     - Add /remove bonding slave devices. 
     - Interogate bonded device stats/configuration
     - Change bonding modes and select balance transmit polices
 4 - Add Link Bonding Library to Doxygen


 app/test-pmd/cmdline.c            |  570 ++++++
 app/test-pmd/config.c             |    4 +-
 app/test-pmd/parameters.c         |    4 +-
 app/test-pmd/testpmd.c            |   37 +-
 app/test-pmd/testpmd.h            |    2 +
 app/test/Makefile                 |    3 +
 app/test/commands.c               |    3 +
 app/test/packet_burst_generator.c |  289 +++
 app/test/packet_burst_generator.h |   78 +
 app/test/test.h                   |    1 +
 app/test/test_link_bonding.c      | 3943 +++++++++++++++++++++++++++++++++++++
 app/test/virtual_pmd.c            |  574 ++++++
 app/test/virtual_pmd.h            |   74 +
 config/common_bsdapp              |    5 +
 config/common_linuxapp            |    5 +
 doc/doxy-api-index.md             |    1 +
 doc/doxy-api.conf                 |    1 +
 lib/Makefile                      |    1 +
 lib/librte_bond/Makefile          |   28 +
 lib/librte_bond/rte_bond.c        | 1682 ++++++++++++++++
 lib/librte_bond/rte_bond.h        |  228 +++
 mk/rte.app.mk                     |    5 +
 22 files changed, 7531 insertions(+), 7 deletions(-)
 create mode 100644 app/test/packet_burst_generator.c
 create mode 100644 app/test/packet_burst_generator.h
 create mode 100644 app/test/test_link_bonding.c
 create mode 100644 app/test/virtual_pmd.c
 create mode 100644 app/test/virtual_pmd.h
 create mode 100644 lib/librte_bond/Makefile
 create mode 100644 lib/librte_bond/rte_bond.c
 create mode 100644 lib/librte_bond/rte_bond.h

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
@ 2014-06-04 15:18   ` declan.doherty
  2014-06-04 15:18     ` declan.doherty
                       ` (2 more replies)
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 2/4] Link bonding unit tests, including: - code to generate packet bursts for testing rx and tx functionality of bonded device - virtual/stubbed out ethdev for use as slave ethdev in testing - checkpack fixes declan.doherty
                     ` (8 subsequent siblings)
  9 siblings, 3 replies; 127+ messages in thread
From: declan.doherty @ 2014-06-04 15:18 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

- Broadcast TX burst broadcast bug fix
- Add/remove slave behavior fix
- Checkpatch fixes

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 config/common_bsdapp       |    5 +
 config/common_linuxapp     |    5 +
 lib/Makefile               |    1 +
 lib/librte_bond/Makefile   |   28 +
 lib/librte_bond/rte_bond.c | 1682 ++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_bond/rte_bond.h |  228 ++++++
 mk/rte.app.mk              |    5 +
 7 files changed, 1954 insertions(+)
 create mode 100644 lib/librte_bond/Makefile
 create mode 100644 lib/librte_bond/rte_bond.c
 create mode 100644 lib/librte_bond/rte_bond.h

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 2cc7b80..53ed8b9 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -187,6 +187,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=y
 
 #
+# Compile link bonding library
+#
+CONFIG_RTE_LIBRTE_BOND=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 62619c6..35b525a 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -211,6 +211,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=n
 
 
+#
+# Compile link bonding library
+#
+CONFIG_RTE_LIBRTE_BOND=y
+
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
diff --git a/lib/Makefile b/lib/Makefile
index b92b392..9995ba8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -47,6 +47,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += librte_pmd_pcap
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
+DIRS-$(CONFIG_RTE_LIBRTE_BOND) += librte_bond
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net
diff --git a/lib/librte_bond/Makefile b/lib/librte_bond/Makefile
new file mode 100644
index 0000000..7514378
--- /dev/null
+++ b/lib/librte_bond/Makefile
@@ -0,0 +1,28 @@
+# <COPYRIGHT_TAG>
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_bond.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_BOND) += rte_bond.c
+
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_bond.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_BOND) += lib/librte_mbuf lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_BOND) += lib/librte_malloc
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_bond/rte_bond.c b/lib/librte_bond/rte_bond.c
new file mode 100644
index 0000000..c079b89
--- /dev/null
+++ b/lib/librte_bond/rte_bond.c
@@ -0,0 +1,1682 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <linux/binfmts.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_memory.h>
+#include <rte_string_fns.h>
+#include <rte_cycles.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_etheraddr.h>
+
+#include "rte_bond.h"
+
+static const char *driver_name = "Link Bonding PMD";
+
+/** Port Queue Mapping Structure */
+struct bond_rx_queue {
+	int queue_id;							/**< Queue Id */
+	struct bond_dev_private *dev_private;	/**< Reference to eth_dev private
+												 structure */
+
+	uint16_t nb_rx_desc;					/**< Number of RX descriptors
+												 available for the queue */
+	struct rte_eth_rxconf rx_conf;			/**< Copy of RX configuration
+												 structure for queue */
+	struct rte_mempool *mb_pool;			/**< Reference to mbuf pool to use
+												 for RX queue */
+};
+
+struct bond_tx_queue {
+	int queue_id;							/**< Queue Id */
+	struct bond_dev_private *dev_private;	/**< Reference to dev private
+												 structure */
+	uint16_t nb_tx_desc;					/**< Number of TX descriptors
+												 available for the queue */
+	struct rte_eth_txconf tx_conf;			/**< 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 */
+};
+
+/** Link Bonding PMD device private configuration Structure */
+struct bond_dev_private {
+	uint8_t mode;						/**< Link Bonding Mode */
+	uint8_t primary_port;				/**< Primary Slave Port */
+	uint8_t balance_xmit_policy;		/**< Transmit policy - l2 / l23 / l34
+											 for operation in balance mode */
+	uint8_t user_defined_mac;			/**< Flag for whether MAC address is
+											 user defined or not */
+	uint8_t promiscuous_en;				/**< Enabled/disable promiscuous mode on
+											slave devices */
+	uint8_t link_props_set;				/**< Bonded eth_dev link properties set*/
+
+	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_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];
+};
+
+static struct slave_conf *
+slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id);
+
+static int
+valid_bonded_ethdev(struct rte_eth_dev *eth_dev)
+{
+	size_t len;
+
+	/* Check valid pointer */
+	if (eth_dev->driver->pci_drv.name == NULL || driver_name == NULL)
+		return -1;
+
+	/* Check string lengths are equal */
+	len = strlen(driver_name);
+	if (strlen(eth_dev->driver->pci_drv.name) != len)
+		return -1;
+
+	/* Compare strings */
+	return strncmp(eth_dev->driver->pci_drv.name, driver_name, len);
+}
+
+static int
+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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+valid_bonded_port_id(uint8_t port_id)
+{
+	/* Verify that port id's are valid */
+	if (valid_port_id(port_id))
+		return -1;
+
+	/* 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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+valid_slave_port_id(uint8_t port_id)
+{
+	/* Verify that port id's are valid */
+	if (valid_port_id(port_id))
+		return -1;
+
+	/* Verify that port_id refers to a non bonded port */
+	if (!valid_bonded_ethdev(&rte_eth_devices[port_id]))
+		return -1;
+
+	return 0;
+}
+
+
+static uint16_t
+bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+
+	uint16_t num_rx_slave = 0;
+	uint16_t num_rx_total = 0;
+
+	int i;
+
+	/* Cast to structure, containing bonded device's port id and queue id */
+	struct bond_rx_queue *bd_rx_q = (struct bond_rx_queue *)queue;
+
+	internals = bd_rx_q->dev_private;
+
+	switch (internals->mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BROADCAST:
+	case BONDING_MODE_BALANCE:
+		for (i = 0; i < internals->active_slave_count; i++) {
+			/* Offset of pointer to *bufs increases as packets are received
+			 * from other slaves */
+			num_rx_slave = rte_eth_rx_burst(internals->active_slaves[i],
+					bd_rx_q->queue_id, bufs + num_rx_total, nb_pkts);
+			if (num_rx_slave)
+				num_rx_total += num_rx_slave;
+		}
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+		num_rx_slave = rte_eth_rx_burst(internals->primary_port,
+				bd_rx_q->queue_id, bufs, nb_pkts);
+		if (num_rx_slave)
+			num_rx_total = num_rx_slave;
+		break;
+	}
+	return num_rx_total;
+}
+
+
+static uint16_t
+bond_ethdev_tx_round_robin(void *queue, struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	struct bond_dev_private *dev_private;
+	struct bond_tx_queue *bd_tx_q;
+
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS][nb_pkts];
+	uint16_t slave_nb_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	static int last_slave_idx = -1;
+	int i, slave_idx;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	dev_private = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = dev_private->active_slave_count;
+	memcpy(slaves, dev_private->active_slaves,
+			sizeof(dev_private->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return num_tx_total;
+
+	/* Populate slaves mbuf with which packets are to be sent on it  */
+	for (i = 0; i < nb_pkts; i++) {
+		slave_idx = i % num_of_slaves;
+		slave_bufs[slave_idx][(slave_nb_pkts[slave_idx])++] = bufs[i];
+	}
+
+	/* calculate the next slave to transmit on based on the last slave idx used
+	 * in the last call to bond_ethdev_tx_burst_round_robin */
+	slave_idx = last_slave_idx + 1;
+
+	/* Send packet burst on each slave device */
+	for (i = 0; i < num_of_slaves; i++) {
+		slave_idx = (slave_idx + i) % num_of_slaves;
+
+		if (slave_nb_pkts[i] > 0) {
+			num_tx_total += rte_eth_tx_burst(slaves[slave_idx],
+					bd_tx_q->queue_id, slave_bufs[i], slave_nb_pkts[i]);
+		}
+	}
+
+	last_slave_idx = slave_idx;
+
+	return num_tx_total;
+}
+
+static uint16_t bond_ethdev_tx_active_backup(void *queue,
+		struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	if (internals->active_slave_count < 1)
+		return 0;
+
+	return rte_eth_tx_burst(internals->primary_port, bd_tx_q->queue_id,
+			bufs, nb_pkts);
+}
+
+
+static inline uint16_t
+ether_hash(struct ether_hdr *eth_hdr)
+{
+	uint16_t *word_src_addr = (uint16_t *)eth_hdr->s_addr.addr_bytes;
+	uint16_t *word_dst_addr = (uint16_t *)eth_hdr->d_addr.addr_bytes;
+
+	return (word_src_addr[0] ^ word_dst_addr[0]) ^
+			(word_src_addr[1] ^ word_dst_addr[1]) ^
+			(word_src_addr[2] ^ word_dst_addr[2]);
+}
+
+static inline uint32_t
+ipv4_hash(struct ipv4_hdr *ipv4_hdr)
+{
+	return (ipv4_hdr->src_addr ^ ipv4_hdr->dst_addr);
+}
+
+static inline uint32_t
+ipv6_hash(struct ipv6_hdr *ipv6_hdr)
+{
+	uint32_t *word_src_addr = (uint32_t *)&(ipv6_hdr->src_addr[0]);
+	uint32_t *word_dst_addr = (uint32_t *)&(ipv6_hdr->dst_addr[0]);
+
+	return (word_src_addr[0] ^ word_dst_addr[0]) ^
+			(word_src_addr[1] ^ word_dst_addr[1]) ^
+			(word_src_addr[2] ^ word_dst_addr[2]) ^
+			(word_src_addr[3] ^ word_dst_addr[3]);
+}
+
+static uint32_t
+udp_hash(struct udp_hdr *hdr)
+{
+	return hdr->src_port ^ hdr->dst_port;
+}
+
+static inline uint16_t
+xmit_slave_hash(const struct rte_mbuf *buf, uint8_t slave_count, uint8_t policy)
+{
+	struct ether_hdr *eth_hdr;
+	struct udp_hdr *udp_hdr;
+	size_t eth_offset = 0;
+	uint32_t hash = 0;
+
+	if (slave_count == 1)
+		return 0;
+
+	switch (policy) {
+	case BALANCE_XMIT_POLICY_LAYER2:
+		eth_hdr = (struct ether_hdr *)buf->pkt.data;
+
+		hash = ether_hash(eth_hdr);
+		hash ^= hash >> 8;
+		return hash % slave_count;
+
+
+	case BALANCE_XMIT_POLICY_LAYER23:
+		eth_hdr = (struct ether_hdr *)buf->pkt.data;
+
+		if (buf->ol_flags & PKT_RX_VLAN_PKT)
+			eth_offset = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_offset = sizeof(struct ether_hdr);
+
+		if (buf->ol_flags & PKT_RX_IPV4_HDR) {
+			struct ipv4_hdr *ipv4_hdr;
+			ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(buf,
+					unsigned char *) + eth_offset);
+
+			hash = ether_hash(eth_hdr) ^ ipv4_hash(ipv4_hdr);
+
+		} else {
+			struct ipv6_hdr *ipv6_hdr;
+
+			ipv6_hdr = (struct ipv6_hdr *)(rte_pktmbuf_mtod(buf,
+					unsigned char *) + eth_offset);
+
+			hash = ether_hash(eth_hdr) ^ ipv6_hash(ipv6_hdr);
+		}
+		break;
+
+	case BALANCE_XMIT_POLICY_LAYER34:
+		if (buf->ol_flags & PKT_RX_VLAN_PKT)
+			eth_offset = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_offset = sizeof(struct ether_hdr);
+
+		if (buf->ol_flags & PKT_RX_IPV4_HDR) {
+			struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)
+					(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset);
+
+			if (ipv4_hdr->next_proto_id == IPPROTO_UDP) {
+				udp_hdr = (struct udp_hdr *)
+						(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset +
+								sizeof(struct ipv4_hdr));
+				hash = ipv4_hash(ipv4_hdr) ^ udp_hash(udp_hdr);
+			} else {
+				hash = ipv4_hash(ipv4_hdr);
+			}
+		} else {
+			struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)
+					(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset);
+
+			if (ipv6_hdr->proto == IPPROTO_UDP) {
+				udp_hdr = (struct udp_hdr *)
+						(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset +
+								sizeof(struct ipv6_hdr));
+				hash = ipv6_hash(ipv6_hdr) ^ udp_hash(udp_hdr);
+			} else {
+				hash = ipv6_hash(ipv6_hdr);
+			}
+		}
+		break;
+	}
+
+	hash ^= hash >> 16;
+	hash ^= hash >> 8;
+
+	return hash % slave_count;
+}
+
+static uint16_t
+bond_ethdev_tx_balance(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	int i, op_slave_id;
+
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS][nb_pkts];
+	uint16_t slave_nb_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = internals->active_slave_count;
+	memcpy(slaves, internals->active_slaves,
+			sizeof(internals->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return num_tx_total;
+
+
+	/* Populate slaves mbuf with the packets which are to be sent on it  */
+	for (i = 0; i < nb_pkts; i++) {
+		/* Select output slave using hash based on xmit policy */
+		op_slave_id = xmit_slave_hash(bufs[i], num_of_slaves,
+				internals->balance_xmit_policy);
+
+		/* Populate slave mbuf arrays with mbufs for that slave */
+		slave_bufs[op_slave_id][slave_nb_pkts[op_slave_id]++] = bufs[i];
+	}
+
+	/* Send packet burst on each slave device */
+	for (i = 0; i < num_of_slaves; i++) {
+		if (slave_nb_pkts[i] > 0) {
+			num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
+					slave_bufs[i], slave_nb_pkts[i]);
+		}
+	}
+
+	return num_tx_total;
+}
+
+static uint16_t
+bond_ethdev_tx_burst_broadcast(void *queue, struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	int i;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = internals->active_slave_count;
+	memcpy(slaves, internals->active_slaves,
+			sizeof(internals->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return 0;
+
+	/* Increment reference count on mbufs */
+	for (i = 0; i < nb_pkts; i++)
+		rte_mbuf_refcnt_update(bufs[i], num_of_slaves - 1);
+
+	/* Transmit burst on each active slave */
+	for (i = 0; i < num_of_slaves; i++)
+		num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
+				bufs, nb_pkts);
+
+	return num_tx_total;
+}
+
+static void
+link_properties_set(struct rte_eth_dev *bonded_eth_dev,
+		struct rte_eth_link *slave_dev_link)
+{
+	struct rte_eth_link *bonded_dev_link = &bonded_eth_dev->data->dev_link;
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	if (slave_dev_link->link_status &&
+		bonded_eth_dev->data->dev_started) {
+		bonded_dev_link->link_duplex = slave_dev_link->link_duplex;
+		bonded_dev_link->link_speed = slave_dev_link->link_speed;
+
+		internals->link_props_set = 1;
+	}
+}
+
+static void
+link_properties_reset(struct rte_eth_dev *bonded_eth_dev)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	memset(&(bonded_eth_dev->data->dev_link), 0,
+			sizeof(bonded_eth_dev->data->dev_link));
+
+	internals->link_props_set = 0;
+}
+
+static int
+link_properties_valid(struct rte_eth_link *bonded_dev_link,
+		struct rte_eth_link *slave_dev_link)
+{
+	if (bonded_dev_link->link_duplex != slave_dev_link->link_duplex ||
+		bonded_dev_link->link_speed !=  slave_dev_link->link_speed)
+		return -1;
+
+	return 0;
+}
+
+static int
+mac_address_set(struct rte_eth_dev *eth_dev, struct ether_addr *new_mac_addr)
+{
+	struct ether_addr *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__);
+		return -1;
+	}
+
+	if (new_mac_addr == NULL) {
+		RTE_LOG(ERR, PMD, "%s: NULL pointer MAC specified\n", __func__);
+		return -1;
+	}
+
+	/* 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));
+
+	return 0;
+}
+
+static int
+mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+	int i;
+
+	/* Update slave devices MAC addresses */
+	if (internals->slave_count < 1)
+		return -1;
+
+	switch (internals->mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+	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]],
+					bonded_eth_dev->data->mac_addrs)) {
+				RTE_LOG(ERR, PMD,
+						"%s: Failed to update port Id %d MAC address\n",
+						__func__, internals->slaves[i]);
+				return -1;
+			}
+		}
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		for (i = 0; i < internals->slave_count; i++) {
+			if (internals->slaves[i] == internals->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->primary_port);
+				}
+			} 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]);
+
+
+					return -1;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+static int
+bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
+{
+	struct bond_dev_private *internals;
+
+	internals = eth_dev->data->dev_private;
+
+	switch (mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_round_robin;
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_active_backup;
+		break;
+	case BONDING_MODE_BALANCE:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_balance;
+		break;
+	case BONDING_MODE_BROADCAST:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_broadcast;
+		break;
+	default:
+		return -1;
+	}
+	internals->mode = mode;
+
+	return 0;
+}
+
+static int
+slave_configure(struct rte_eth_dev *bonded_eth_dev,
+		struct rte_eth_dev *slave_eth_dev)
+{
+	struct bond_rx_queue *bd_rx_q;
+	struct bond_tx_queue *bd_tx_q;
+
+	int 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;
+
+	if (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;
+	}
+
+	/* 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,
+				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;
+		}
+	}
+
+	/* Setup Tx Queues */
+	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,
+				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;
+		}
+	}
+
+	/* 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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static 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;
+}
+
+static void
+slave_config_clear(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) {
+			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]));
+		}
+	}
+}
+
+static void
+slave_config_store(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];
+
+	presisted_slave_conf->port_id = slave_eth_dev->data->port_id;
+
+	memcpy(&(presisted_slave_conf->mac_addr), slave_eth_dev->data->mac_addrs,
+			sizeof(struct ether_addr));
+}
+
+static void
+bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev);
+
+static int
+bond_ethdev_start(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals;
+	int i;
+
+	/* 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);
+		return -1;
+	}
+
+	eth_dev->data->dev_link.link_status = 1;
+	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__);
+		return -1;
+	}
+
+	if (internals->user_defined_mac == 0) {
+		struct slave_conf *conf = slave_config_get(internals,
+				internals->primary_port);
+
+		if (mac_address_set(eth_dev, &(conf->mac_addr)) != 0) {
+			RTE_LOG(ERR, PMD,
+					"bonded port (%d) failed to update mac address",
+					eth_dev->data->port_id);
+			return -1;
+		}
+	}
+
+	/* Update all slave devices MACs*/
+	if (mac_address_slaves_update(eth_dev) != 0)
+		return -1;
+
+	/* If bonded device is configure in promiscuous mode then re-apply config */
+	if (internals->promiscuous_en)
+		bond_ethdev_promiscuous_enable(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)",
+					eth_dev->data->port_id, internals->slaves[i]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static void
+bond_ethdev_stop(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals = eth_dev->data->dev_private;
+
+	internals->active_slave_count = 0;
+
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_started = 0;
+}
+
+static void
+bond_ethdev_close(struct rte_eth_dev *dev __rte_unused)
+{
+}
+
+static int
+bond_ethdev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static void
+bond_ethdev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
+{
+	dev_info->driver_name = driver_name;
+	dev_info->max_mac_addrs = 1;
+
+	dev_info->max_rx_pktlen = (uint32_t)2048;
+
+	dev_info->max_rx_queues = (uint16_t)128;
+	dev_info->max_tx_queues = (uint16_t)512;
+
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = dev->pci_dev;
+}
+
+static int
+bond_ethdev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc, unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool)
+{
+	struct bond_rx_queue *bd_rx_q = (struct bond_rx_queue *)
+			rte_zmalloc_socket(NULL, sizeof(struct bond_rx_queue),
+					0, dev->pci_dev->numa_node);
+	if (bd_rx_q == NULL)
+		return -1;
+
+	bd_rx_q->queue_id = rx_queue_id;
+	bd_rx_q->dev_private = dev->data->dev_private;
+
+	bd_rx_q->nb_rx_desc = nb_rx_desc;
+
+	memcpy(&(bd_rx_q->rx_conf), rx_conf, sizeof(struct rte_eth_rxconf));
+	bd_rx_q->mb_pool = mb_pool;
+
+	dev->data->rx_queues[rx_queue_id] = bd_rx_q;
+
+	return 0;
+}
+
+static int
+bond_ethdev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc, unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf)
+{
+	struct bond_tx_queue *bd_tx_q  = (struct bond_tx_queue *)
+			rte_zmalloc_socket(NULL, sizeof(struct bond_tx_queue),
+					0, dev->pci_dev->numa_node);
+
+	if (bd_tx_q == NULL)
+			return -1;
+
+	bd_tx_q->queue_id = tx_queue_id;
+	bd_tx_q->dev_private = dev->data->dev_private;
+
+	bd_tx_q->nb_tx_desc = nb_tx_desc;
+	memcpy(&(bd_tx_q->tx_conf), tx_conf, sizeof(bd_tx_q->tx_conf));
+
+	dev->data->tx_queues[tx_queue_id] = bd_tx_q;
+
+	return 0;
+}
+
+static void
+bond_ethdev_rx_queue_release(void *queue)
+{
+	if (queue == NULL)
+		return;
+
+	rte_free(queue);
+}
+
+static void
+bond_ethdev_tx_queue_release(void *queue)
+{
+	if (queue == NULL)
+		return;
+
+	rte_free(queue);
+}
+
+
+static int
+bond_ethdev_link_update(struct rte_eth_dev *bonded_eth_dev,
+		int wait_to_complete)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	if (!bonded_eth_dev->data->dev_started ||
+		internals->active_slave_count == 0) {
+		bonded_eth_dev->data->dev_link.link_status = 0;
+		return 0;
+	} else {
+		struct rte_eth_dev *slave_eth_dev;
+		int i, link_up = 0;
+
+		for (i = 0; i < internals->active_slave_count; i++) {
+			slave_eth_dev = &rte_eth_devices[internals->active_slaves[i]];
+
+			(*slave_eth_dev->dev_ops->link_update)(slave_eth_dev,
+					wait_to_complete);
+			if (slave_eth_dev->data->dev_link.link_status == 1) {
+				link_up = 1;
+				break;
+			}
+		}
+
+		bonded_eth_dev->data->dev_link.link_status = link_up;
+	}
+
+	return 0;
+}
+
+static void
+bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	struct rte_eth_stats slave_stats;
+
+	int i;
+
+	/* clear bonded stats before populating from slaves */
+	memset(stats, 0, sizeof(*stats));
+
+	for (i = 0; i < internals->slave_count; i++) {
+		rte_eth_stats_get(internals->slaves[i], &slave_stats);
+
+		stats->ipackets += slave_stats.ipackets;
+		stats->opackets += slave_stats.opackets;
+		stats->ibytes += slave_stats.ibytes;
+		stats->obytes += slave_stats.obytes;
+		stats->ierrors += slave_stats.ierrors;
+		stats->oerrors += slave_stats.oerrors;
+		stats->imcasts += slave_stats.imcasts;
+		stats->rx_nombuf += slave_stats.rx_nombuf;
+		stats->fdirmatch += slave_stats.fdirmatch;
+		stats->fdirmiss += slave_stats.fdirmiss;
+		stats->tx_pause_xon += slave_stats.tx_pause_xon;
+		stats->rx_pause_xon += slave_stats.rx_pause_xon;
+		stats->tx_pause_xoff += slave_stats.tx_pause_xoff;
+		stats->rx_pause_xoff += slave_stats.rx_pause_xoff;
+	}
+}
+
+static void
+bond_ethdev_stats_reset(struct rte_eth_dev *dev)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < internals->slave_count; i++)
+		rte_eth_stats_reset(internals->slaves[i]);
+}
+
+static void
+bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals = eth_dev->data->dev_private;
+	int i;
+
+	internals->promiscuous_en = 1;
+
+	switch (internals->mode) {
+	/* Promiscuous mode is propagated to all slaves */
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BALANCE:
+	case BONDING_MODE_BROADCAST:
+		for (i = 0; i < internals->slave_count; i++)
+			rte_eth_promiscuous_enable(internals->slaves[i]);
+		break;
+	/* Promiscuous mode is propagated only to primary slave */
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		rte_eth_promiscuous_enable(internals->primary_port);
+
+	}
+}
+
+static void
+bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	int i;
+
+	internals->promiscuous_en = 0;
+
+	switch (internals->mode) {
+	/* Promiscuous mode is propagated to all slaves */
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BALANCE:
+	case BONDING_MODE_BROADCAST:
+		for (i = 0; i < internals->slave_count; i++)
+			rte_eth_promiscuous_disable(internals->slaves[i]);
+		break;
+	/* Promiscuous mode is propagated only to primary slave */
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		rte_eth_promiscuous_disable(internals->primary_port);
+	}
+}
+
+
+static void
+bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,
+		void *param)
+{
+	struct rte_eth_dev *bonded_eth_dev, *slave_eth_dev;
+	struct bond_dev_private *internals;
+	struct rte_eth_link link;
+
+	int i, bonded_port_id, valid_slave, active_pos = -1;
+
+	if (type != RTE_ETH_EVENT_INTR_LSC)
+		return;
+
+	if (param == NULL)
+		return;
+
+	bonded_port_id = *(uint8_t *)param;
+
+	bonded_eth_dev = &rte_eth_devices[bonded_port_id];
+	slave_eth_dev = &rte_eth_devices[port_id];
+
+	if (valid_bonded_ethdev(bonded_eth_dev))
+		return;
+
+	internals = bonded_eth_dev->data->dev_private;
+
+	/* If the device isn't started don't handle interrupts */
+	if (!bonded_eth_dev->data->dev_started)
+		return;
+
+	/* 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) {
+			valid_slave = 1;
+			break;
+		}
+	}
+
+	if (!valid_slave)
+		return;
+
+	/* Search for port in active port list */
+	for (i = 0; i < internals->active_slave_count; i++) {
+		if (port_id == internals->active_slaves[i]) {
+			active_pos = i;
+			break;
+		}
+	}
+
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status) {
+		if (active_pos == -1) {
+			/* if no active slave ports then set this port to be primary port */
+			if (internals->active_slave_count == 0) {
+				/* If first active slave, then change link status */
+				bonded_eth_dev->data->dev_link.link_status = 1;
+				internals->primary_port = port_id;
+
+				/* Inherit eth dev link properties from first active slave */
+				link_properties_set(bonded_eth_dev,
+						&(slave_eth_dev->data->dev_link));
+
+			}
+			internals->active_slaves[internals->active_slave_count++] = port_id;
+		}
+	} else {
+		if (active_pos != -1) {
+			/* Remove from active slave list */
+			for (i = active_pos; i < (internals->active_slave_count - 1); i++)
+				internals->active_slaves[i] = internals->active_slaves[i+1];
+
+			internals->active_slave_count--;
+
+			/* No active slaves, change link status to down and reset other
+			 * link properties */
+			if (internals->active_slave_count == 0)
+				link_properties_reset(bonded_eth_dev);
+
+			/* Update primary id, take first active slave from list or if none
+			 * available set to -1 */
+			if (port_id == internals->primary_port) {
+				if (internals->active_slave_count > 0)
+					internals->primary_port = internals->active_slaves[0];
+				else
+					internals->primary_port = internals->slaves[0];
+			}
+		}
+	}
+}
+
+static struct eth_dev_ops default_dev_ops = {
+		.dev_start = bond_ethdev_start,
+		.dev_stop = bond_ethdev_stop,
+		.dev_close = bond_ethdev_close,
+		.dev_configure = bond_ethdev_configure,
+		.dev_infos_get = bond_ethdev_info,
+		.rx_queue_setup = bond_ethdev_rx_queue_setup,
+		.tx_queue_setup = bond_ethdev_tx_queue_setup,
+		.rx_queue_release = bond_ethdev_rx_queue_release,
+		.tx_queue_release = bond_ethdev_tx_queue_release,
+		.link_update = bond_ethdev_link_update,
+		.stats_get = bond_ethdev_stats_get,
+		.stats_reset = bond_ethdev_stats_reset,
+		.promiscuous_enable = bond_ethdev_promiscuous_enable,
+		.promiscuous_disable = bond_ethdev_promiscuous_disable
+};
+
+static uint8_t
+number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; ((i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL)); i++) {
+		if (sockets < ms[i].socket_id)
+			sockets = ms[i].socket_id;
+	}
+
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+
+}
+
+int
+rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
+{
+	struct rte_pci_device *pci_dev = NULL;
+	struct bond_dev_private *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct eth_driver *eth_drv = NULL;
+	struct rte_pci_driver *pci_drv = NULL;
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+
+	if (name == NULL) {
+		RTE_LOG(ERR, PMD, "Invalid name specified\n");
+		goto err;
+	}
+
+	if (socket_id >= number_of_sockets()) {
+		RTE_LOG(ERR, PMD,
+				"%s: invalid socket id specified to create bonded device on.\n",
+				__func__);
+		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");
+		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");
+		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");
+		goto err;
+	}
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, socket_id);
+	if (internals == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to malloc internals on socket");
+		goto err;
+	}
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate();
+	if (eth_dev == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to allocate rte_eth_dev");
+		goto err;
+	}
+
+	pci_dev->numa_node = socket_id;
+	pci_drv->name = driver_name;
+
+	eth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);
+	eth_dev->driver = eth_drv;
+
+	eth_dev->data->dev_private = internals;
+	eth_dev->data->nb_rx_queues = (uint16_t)1;
+	eth_dev->data->nb_tx_queues = (uint16_t)1;
+
+	eth_dev->data->dev_link.link_status = 0;
+
+	eth_dev->data->mac_addrs = rte_zmalloc(name, ETHER_ADDR_LEN, 0);
+
+	eth_dev->data->dev_started = 0;
+	eth_dev->data->promiscuous = 0;
+	eth_dev->data->scattered_rx = 0;
+	eth_dev->data->all_multicast = 0;
+
+	eth_dev->dev_ops = &default_dev_ops;
+	eth_dev->pci_dev = pci_dev;
+
+	eth_dev->rx_pkt_burst = bond_ethdev_rx_burst;
+	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);
+		goto err;
+	}
+
+	internals->primary_port = 0;
+	internals->balance_xmit_policy = BALANCE_XMIT_POLICY_LAYER2;
+	internals->user_defined_mac = 0;
+	internals->link_props_set = 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:
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (pci_drv)
+		rte_free(pci_drv);
+	if (eth_drv)
+		rte_free(eth_drv);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+
+
+int
+rte_eth_bond_slave_add(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;
+	struct bond_dev_private *temp_internals;
+	struct rte_eth_link link_props;
+
+	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;
+
+	/*
+	 * 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;
+			}
+		}
+	}
+
+	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);
+
+	if (internals->slave_count < 1) {
+		/* 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));
+
+		/* Make primary slave */
+		internals->primary_port = slave_port_id;
+	} else {
+		/* Check slave link properties are supported if props are set,
+		 * all slaves must be the same */
+		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;
+			}
+		} else {
+			link_properties_set(bonded_eth_dev,
+					&(slave_eth_dev->data->dev_link));
+		}
+	}
+
+	internals->slave_count++;
+
+	/* Update all slave devices MACs*/
+	mac_address_slaves_update(bonded_eth_dev);
+
+	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",
+					slave_port_id);
+			goto err_add;
+		}
+	}
+
+	/* Register link status change callback with bonded device pointer as
+	 * argument*/
+	rte_eth_dev_callback_register(slave_port_id, RTE_ETH_EVENT_INTR_LSC,
+			bond_ethdev_lsc_event_callback, &bonded_eth_dev->data->port_id);
+
+	/* If bonded device is started then we can add the slave to our active
+	 * slave array */
+	if (bonded_eth_dev->data->dev_started) {
+		rte_eth_link_get_nowait(slave_port_id, &link_props);
+
+		 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)
+{
+	struct bond_dev_private *internals;
+	struct slave_conf *slave_conf;
+
+	int i;
+	int pos = -1;
+
+	/* Verify that port id's are valid bonded and slave ports */
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		goto err_del;
+
+	if (valid_slave_port_id(slave_port_id) != 0)
+		goto err_del;
+
+	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;
+
+		/* shift active slaves up active array list */
+		if (pos >= 0 && i < (internals->active_slave_count - 1))
+			internals->active_slaves[i] = internals->active_slaves[i+1];
+	}
+
+	if (pos >= 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;
+
+		/* shift slaves up list */
+		if (pos >= 0 && i < internals->slave_count)
+			internals->slaves[i] = internals->slaves[i+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,
+			bond_ethdev_lsc_event_callback,
+			&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));
+
+	slave_config_clear(internals, &rte_eth_devices[slave_port_id]);
+
+	internals->slave_count--;
+
+	/*  first slave in the active list will be the primary by default,
+	 *  otherwise use first device in list */
+	if (internals->primary_port == slave_port_id) {
+		if (internals->active_slave_count > 0)
+			internals->primary_port = internals->active_slaves[0];
+		else if (internals->slave_count > 0)
+			internals->primary_port = internals->slaves[0];
+		else
+			internals->primary_port = 0;
+	}
+
+	if (internals->active_slave_count < 1) {
+		/* reset device link properties as no slaves are active */
+		link_properties_reset(&rte_eth_devices[bonded_port_id]);
+
+		/* if no slaves are any longer attached to bonded device and MAC is not
+		 * user defined then clear MAC of bonded device as it will be reset
+		 * when a new slave is added */
+		if (internals->slave_count < 1 && !internals->user_defined_mac)
+			memset(rte_eth_devices[bonded_port_id].data->mac_addrs, 0,
+					sizeof(*(rte_eth_devices[bonded_port_id].data->mac_addrs)));
+	}
+
+	return 0;
+
+err_del:
+	RTE_LOG(ERR, PMD,
+			"Cannot remove slave device (not present in bonded device)\n");
+	return -1;
+
+}
+
+int
+rte_eth_bond_mode_set(uint8_t bonded_port_id, uint8_t mode)
+{
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	return bond_ethdev_mode_set(&rte_eth_devices[bonded_port_id], mode);
+}
+
+
+int
+rte_eth_bond_mode_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->mode;
+}
+
+int
+rte_eth_bond_primary_set(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+	struct bond_dev_private *internals;
+	int i;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (valid_slave_port_id(slave_port_id) != 0)
+		return -1;
+
+	internals =  rte_eth_devices[bonded_port_id].data->dev_private;
+
+	/* Search bonded device slave ports for new proposed primary port */
+	for (i = 0; i < internals->slave_count; i++) {
+		if (internals->slaves[i] == slave_port_id) {
+			/* Found slave device in active slave list */
+			internals->primary_port = slave_port_id;
+			return 0;
+		}
+	}
+
+	/* Slave is not bound to this master device */
+	return -1;
+}
+
+int
+rte_eth_bond_primary_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;
+
+	if (internals->slave_count < 1)
+		return -1;
+
+	return internals->primary_port;
+}
+
+int
+rte_eth_bond_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves)
+{
+	struct bond_dev_private *internals;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (slaves == NULL)
+		return -1;
+
+	internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+	*slaves = (uint8_t *)(&internals->slaves);
+
+	return internals->slave_count;
+
+}
+
+int
+rte_eth_bond_active_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves)
+{
+	struct bond_dev_private *internals;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (slaves == NULL)
+		return -1;
+
+	internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+	*slaves = (uint8_t *)(&internals->active_slaves);
+
+	return internals->active_slave_count;
+
+}
+
+
+int
+rte_eth_bond_mac_address_set(uint8_t bonded_port_id,
+		struct ether_addr *mac_addr)
+{
+	struct rte_eth_dev *bonded_eth_dev;
+	struct bond_dev_private *internals;
+
+	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;
+
+	/* Set MAC Address of Bonded Device */
+	if (mac_address_set(bonded_eth_dev, mac_addr))
+		return -1;
+
+	internals->user_defined_mac = 1;
+
+	/* Update all slave devices MACs*/
+	if (internals->slave_count > 0)
+		return mac_address_slaves_update(bonded_eth_dev);
+
+	return 0;
+}
+
+
+int
+rte_eth_bond_mac_address_reset(uint8_t bonded_port_id)
+{
+	struct rte_eth_dev *bonded_eth_dev;
+	struct bond_dev_private *internals;
+
+
+	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;
+
+	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)
+			return -1;
+
+		/* Update all slave devices MAC addresses */
+		return mac_address_slaves_update(bonded_eth_dev);
+	}
+	/* No need to update anything as no slaves present */
+	return 0;
+}
+
+int
+rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy)
+{
+	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;
+
+	switch (policy) {
+	case BALANCE_XMIT_POLICY_LAYER2:
+	case BALANCE_XMIT_POLICY_LAYER23:
+	case BALANCE_XMIT_POLICY_LAYER34:
+		internals->balance_xmit_policy = policy;
+		break;
+
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+
+int
+rte_eth_bond_xmit_policy_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->balance_xmit_policy;
+}
diff --git a/lib/librte_bond/rte_bond.h b/lib/librte_bond/rte_bond.h
new file mode 100644
index 0000000..97b6d5e
--- /dev/null
+++ b/lib/librte_bond/rte_bond.h
@@ -0,0 +1,228 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_BOND_H_
+#define _RTE_ETH_BOND_H_
+
+/**
+ * @file
+ * RTE Link Bonding Ethernet Device
+ * Link Bonding for 1GbE and 10GbE ports to allow the aggregation of multiple
+ * (slave) NICs into a single logical interface. The bonded device processes
+ * these interfaces based on the mode of operation specified and supported.
+ * This implementation supports 4 modes of operation round robin, active backup
+ * balance and broadcast. Providing redundant links, fault tolerance and/or
+ * load balancing of network ports
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ether.h>
+
+/** Link Bonding Mode Definitions */
+#define BONDING_MODE_ROUND_ROBIN		(0)
+#define BONDING_MODE_ACTIVE_BACKUP		(1)
+#define BONDING_MODE_BALANCE			(2)
+#define BONDING_MODE_BROADCAST			(3)
+
+/** Balance Mode Transmit Policy Types */
+#define BALANCE_XMIT_POLICY_LAYER2		(0)
+#define BALANCE_XMIT_POLICY_LAYER23		(1)
+#define BALANCE_XMIT_POLICY_LAYER34		(2)
+
+/**
+ * Create a bonded rte_eth_dev device
+ *
+ * @param name
+ * @param mode
+ * @param socket_id
+ *
+ * @return
+ *	Port Id of created rte_eth_dev on success, negative value otherwise
+ */
+int
+rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id);
+
+/**
+ * Add a rte_eth_dev device as a slave to the bonded device
+ *
+ * @param bonded_port_id
+ * @param slave_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Remove a slave rte_eth_dev device from the bonded device
+ *
+ * @param bonded_port_id
+ * @param slave_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Set link bonding mode of bonded device
+ *
+ * @param bonded_port_id
+ * @param mode
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mode_set(uint8_t bonded_port_id, uint8_t mode);
+
+/**
+ * Get link bonding mode of bonded device
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	link bonding mode on success, negative value otherwise
+ */
+int
+rte_eth_bond_mode_get(uint8_t bonded_port_id);
+
+/**
+ * Set slave rte_eth_dev as primary slave of bonded device
+ *
+ * @param bonded_port_id
+ * @param slave_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_primary_set(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Get primary slave of bonded device
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	Port Id of primary slave on success, -1 on failure
+ */
+int
+rte_eth_bond_primary_get(uint8_t bonded_port_id);
+
+/**
+ * Populate an array with list of the slaves port id's of the bonded device
+ *
+ * @param bonded_port_id
+ * @param slaves
+ *
+ * @return
+ *	number of slaves associated with bonded device on success,
+ *	negative value otherwise
+ */
+int
+rte_eth_bond_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves);
+
+/**
+ * Populate an array with list of the active slaves port id's of the bonded
+ * device.
+ *
+ * @param bonded_port_id
+ * @param slaves
+ *
+ * @return
+ *	number of active slaves associated with bonded device on success,
+ *	negative value otherwise
+ */
+int
+rte_eth_bond_active_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves);
+
+/**
+ * Set explicit MAC address to use on bonded device and it's slaves.
+ *
+ * @param bonded_port_id
+ * @param mac_addr
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mac_address_set(uint8_t bonded_port_id,
+		struct ether_addr *mac_addr);
+
+/**
+ * Reset bonded device to use MAC from primary slave on bonded device and it's
+ * slaves.
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mac_address_reset(uint8_t bonded_port_id);
+
+/**
+ * Set the transmit policy for bonded device to use when it is operating in
+ * balance mode
+ *
+ * @param bonded_port_id
+ * @param policy
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy);
+
+/**
+ * Get the transmit policy set on bonded device for balance mode operation
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	balance transmit policy on success, negative value otherwise
+ */
+int
+rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index a836577..a803a5c 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -177,8 +177,13 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_PCAP),y)
 LDLIBS += -lrte_pmd_pcap -lpcap
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_BOND),y)
+LDLIBS += -lrte_bond
 endif
 
+endif
+
+
 LDLIBS += $(EXECENV_LDLIBS)
 
 LDLIBS += --end-group
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v2 2/4] Link bonding unit tests, including: - code to generate packet bursts for testing rx and tx functionality of bonded device - virtual/stubbed out ethdev for use as slave ethdev in testing - checkpack fixes
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 1/4] " declan.doherty
@ 2014-06-04 15:18   ` declan.doherty
  2014-06-04 15:18     ` declan.doherty
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 0/4] Link Bonding Library declan.doherty
                     ` (7 subsequent siblings)
  9 siblings, 1 reply; 127+ messages in thread
From: declan.doherty @ 2014-06-04 15:18 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 app/test/Makefile                 |    3 +
 app/test/commands.c               |    3 +
 app/test/packet_burst_generator.c |  289 +++
 app/test/packet_burst_generator.h |   78 +
 app/test/test.h                   |    1 +
 app/test/test_link_bonding.c      | 3943 +++++++++++++++++++++++++++++++++++++
 app/test/virtual_pmd.c            |  574 ++++++
 app/test/virtual_pmd.h            |   74 +
 8 files changed, 4965 insertions(+)
 create mode 100644 app/test/packet_burst_generator.c
 create mode 100644 app/test/packet_burst_generator.h
 create mode 100644 app/test/test_link_bonding.c
 create mode 100644 app/test/virtual_pmd.c
 create mode 100644 app/test/virtual_pmd.h

diff --git a/app/test/Makefile b/app/test/Makefile
index b49785e..ac55a11 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_ring_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_rwlock.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_timer.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_mempool.c
+SRCS-$(CONFIG_RTE_APP_TEST) += test_link_bonding.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_mempool_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_mbuf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_logs.c
@@ -94,6 +95,8 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_common.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_timer_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_ivshmem.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_devargs.c
+SRCS-$(CONFIG_RTE_APP_TEST) += virtual_pmd.c
+SRCS-$(CONFIG_RTE_APP_TEST) += packet_burst_generator.c
 
 ifeq ($(CONFIG_RTE_APP_TEST),y)
 SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
diff --git a/app/test/commands.c b/app/test/commands.c
index efa8566..4d0ec3b 100644
--- a/app/test/commands.c
+++ b/app/test/commands.c
@@ -157,6 +157,8 @@ static void cmd_autotest_parsed(void *parsed_result,
 		ret = test_timer();
 	if (!strcmp(res->autotest, "timer_perf_autotest"))
 		ret = test_timer_perf();
+	if (!strcmp(res->autotest, "link_bonding_autotest"))
+		ret = test_link_bonding();
 	if (!strcmp(res->autotest, "mempool_autotest"))
 		ret = test_mempool();
 	if (!strcmp(res->autotest, "mempool_perf_autotest"))
@@ -221,6 +223,7 @@ cmdline_parse_token_string_t cmd_autotest_autotest =
 			"alarm_autotest#interrupt_autotest#"
 			"version_autotest#eal_fs_autotest#"
 			"cmdline_autotest#func_reentrancy_autotest#"
+			"link_bonding_autotest#"
 			"mempool_perf_autotest#hash_perf_autotest#"
 			"memcpy_perf_autotest#ring_perf_autotest#"
 			"red_autotest#meter_autotest#sched_autotest#"
diff --git a/app/test/packet_burst_generator.c b/app/test/packet_burst_generator.c
new file mode 100644
index 0000000..8c535f6
--- /dev/null
+++ b/app/test/packet_burst_generator.c
@@ -0,0 +1,289 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_byteorder.h>
+#include <rte_mbuf.h>
+
+#include "packet_burst_generator.h"
+
+#define UDP_SRC_PORT 1024
+#define UDP_DST_PORT 1024
+
+
+#define IP_DEFTTL  64   /* from RFC 1340. */
+#define IP_VERSION 0x40
+#define IP_HDRLEN  0x05 /* default IP header length == five 32-bits words. */
+#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
+
+static void
+copy_buf_to_pkt_segs(void *buf, unsigned len, struct rte_mbuf *pkt,
+		unsigned offset)
+{
+	struct rte_mbuf *seg;
+	void *seg_buf;
+	unsigned copy_len;
+
+	seg = pkt;
+	while (offset >= seg->pkt.data_len) {
+		offset -= seg->pkt.data_len;
+		seg = seg->pkt.next;
+	}
+	copy_len = seg->pkt.data_len - offset;
+	seg_buf = ((char *) seg->pkt.data + offset);
+	while (len > copy_len) {
+		rte_memcpy(seg_buf, buf, (size_t) copy_len);
+		len -= copy_len;
+		buf = ((char *) buf + copy_len);
+		seg = seg->pkt.next;
+		seg_buf = seg->pkt.data;
+	}
+	rte_memcpy(seg_buf, buf, (size_t) len);
+}
+
+static inline void
+copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
+{
+	if (offset + len <= pkt->pkt.data_len) {
+		rte_memcpy(((char *) pkt->pkt.data + offset), buf, (size_t) len);
+		return;
+	}
+	copy_buf_to_pkt_segs(buf, len, pkt, offset);
+}
+
+
+void
+initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint8_t vlan_enabled, uint16_t van_id)
+{
+	ether_addr_copy(dst_mac, &eth_hdr->d_addr);
+	ether_addr_copy(src_mac, &eth_hdr->s_addr);
+
+	if (vlan_enabled) {
+		struct vlan_hdr *vhdr = (struct vlan_hdr *)((uint8_t *)eth_hdr +
+				sizeof(struct ether_hdr));
+
+		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+
+		vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		vhdr->vlan_tci = van_id;
+	} else {
+		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	}
+
+}
+
+uint16_t
+initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
+		uint16_t dst_port, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct udp_hdr));
+
+	udp_hdr->src_port = rte_cpu_to_be_16(src_port);
+	udp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
+	udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len);
+	udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
+
+	return pkt_len;
+}
+
+
+uint16_t
+initialize_ipv6_header(struct ipv6_hdr *ip_hdr, uint8_t *src_addr,
+		uint8_t *dst_addr, uint16_t pkt_data_len)
+{
+	ip_hdr->vtc_flow = 0;
+	ip_hdr->payload_len = pkt_data_len;
+	ip_hdr->proto = IPPROTO_UDP;
+	ip_hdr->hop_limits = IP_DEFTTL;
+
+	rte_memcpy(ip_hdr->src_addr, src_addr, sizeof(ip_hdr->src_addr));
+	rte_memcpy(ip_hdr->dst_addr, dst_addr, sizeof(ip_hdr->dst_addr));
+
+	return (uint16_t) (pkt_data_len + sizeof(struct ipv6_hdr));
+}
+
+uint16_t
+initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+		uint32_t dst_addr, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+	uint16_t *ptr16;
+	uint32_t ip_cksum;
+
+	/*
+	 * Initialize IP header.
+	 */
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct ipv4_hdr));
+
+	ip_hdr->version_ihl   = IP_VHL_DEF;
+	ip_hdr->type_of_service   = 0;
+	ip_hdr->fragment_offset = 0;
+	ip_hdr->time_to_live   = IP_DEFTTL;
+	ip_hdr->next_proto_id = IPPROTO_UDP;
+	ip_hdr->packet_id = 0;
+	ip_hdr->total_length   = rte_cpu_to_be_16(pkt_len);
+	ip_hdr->src_addr = rte_cpu_to_be_32(src_addr);
+	ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr);
+
+	/*
+	 * Compute IP header checksum.
+	 */
+	ptr16 = (uint16_t *)ip_hdr;
+	ip_cksum = 0;
+	ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
+	ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
+	ip_cksum += ptr16[4];
+	ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
+	ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
+
+	/*
+	 * Reduce 32 bit checksum to 16 bits and complement it.
+	 */
+	ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
+		(ip_cksum & 0x0000FFFF);
+	if (ip_cksum > 65535)
+		ip_cksum -= 65535;
+	ip_cksum = (~ip_cksum) & 0x0000FFFF;
+	if (ip_cksum == 0)
+		ip_cksum = 0xFFFF;
+	ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
+
+	return pkt_len;
+}
+
+
+
+/*
+ * The maximum number of segments per packet is used when creating
+ * scattered transmit packets composed of a list of mbufs.
+ */
+#define RTE_MAX_SEGS_PER_PKT 255 /**< pkt.nb_segs is a 8-bit unsigned char. */
+
+#define TXONLY_DEF_PACKET_LEN 64
+#define TXONLY_DEF_PACKET_LEN_128 128
+
+uint16_t tx_pkt_length = TXONLY_DEF_PACKET_LEN;
+uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT] = {
+		TXONLY_DEF_PACKET_LEN_128,
+};
+
+uint8_t  tx_pkt_nb_segs = 1;
+
+int
+generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
+		struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr,
+		uint8_t ipv4, struct udp_hdr *udp_hdr, int nb_pkt_per_burst)
+{
+	int i, nb_pkt = 0;
+	size_t eth_hdr_size;
+
+	struct rte_mbuf *pkt_seg;
+	struct rte_mbuf *pkt;
+
+	for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+		pkt = rte_pktmbuf_alloc(mp);
+		if (pkt == NULL) {
+nomore_mbuf:
+			if (nb_pkt == 0)
+				return -1;
+			break;
+		}
+
+		pkt->pkt.data_len = tx_pkt_seg_lengths[0];
+		pkt_seg = pkt;
+		for (i = 1; i < tx_pkt_nb_segs; i++) {
+			pkt_seg->pkt.next = rte_pktmbuf_alloc(mp);
+			if (pkt_seg->pkt.next == NULL) {
+				pkt->pkt.nb_segs = i;
+				rte_pktmbuf_free(pkt);
+				goto nomore_mbuf;
+			}
+			pkt_seg = pkt_seg->pkt.next;
+			pkt_seg->pkt.data_len = tx_pkt_seg_lengths[i];
+		}
+		pkt_seg->pkt.next = NULL; /* Last segment of packet. */
+
+		/*
+		 * Copy headers in first packet segment(s).
+		 */
+		if (vlan_enabled)
+			eth_hdr_size = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_hdr_size = sizeof(struct ether_hdr);
+
+		copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0);
+
+		if (ipv4) {
+			copy_buf_to_pkt(ip_hdr, sizeof(struct ipv4_hdr), pkt, eth_hdr_size);
+			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size +
+					sizeof(struct ipv4_hdr));
+		} else {
+			copy_buf_to_pkt(ip_hdr, sizeof(struct ipv6_hdr), pkt, eth_hdr_size);
+			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size +
+					sizeof(struct ipv6_hdr));
+		}
+
+		/*
+		 * Complete first mbuf of packet and append it to the
+		 * burst of packets to be transmitted.
+		 */
+		pkt->pkt.nb_segs = tx_pkt_nb_segs;
+		pkt->pkt.pkt_len = tx_pkt_length;
+		pkt->pkt.vlan_macip.f.l2_len = eth_hdr_size;
+
+		if (ipv4) {
+			pkt->pkt.vlan_macip.f.vlan_tci  = ETHER_TYPE_IPv4;
+			pkt->pkt.vlan_macip.f.l3_len = sizeof(struct ipv4_hdr);
+
+			if (vlan_enabled)
+				pkt->ol_flags = PKT_RX_IPV4_HDR | PKT_RX_VLAN_PKT;
+			else
+				pkt->ol_flags = PKT_RX_IPV4_HDR;
+		} else {
+			pkt->pkt.vlan_macip.f.vlan_tci  = ETHER_TYPE_IPv6;
+			pkt->pkt.vlan_macip.f.l3_len = sizeof(struct ipv6_hdr);
+
+			if (vlan_enabled)
+				pkt->ol_flags = PKT_RX_IPV6_HDR | PKT_RX_VLAN_PKT;
+			else
+				pkt->ol_flags = PKT_RX_IPV6_HDR;
+		}
+
+		pkts_burst[nb_pkt] = pkt;
+	}
+
+	return nb_pkt;
+}
+
diff --git a/app/test/packet_burst_generator.h b/app/test/packet_burst_generator.h
new file mode 100644
index 0000000..5b3cd6c
--- /dev/null
+++ b/app/test/packet_burst_generator.h
@@ -0,0 +1,78 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PACKET_BURST_GENERATOR_H_
+#define PACKET_BURST_GENERATOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+
+
+#define IPV4_ADDR(a, b, c, d)(((a & 0xff) << 24) | ((b & 0xff) << 16) | \
+		((c & 0xff) << 8) | (d & 0xff))
+
+
+void
+initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint8_t vlan_enabled, uint16_t van_id);
+
+uint16_t
+initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
+		uint16_t dst_port, uint16_t pkt_data_len);
+
+
+uint16_t
+initialize_ipv6_header(struct ipv6_hdr *ip_hdr, uint8_t *src_addr,
+		uint8_t *dst_addr, uint16_t pkt_data_len);
+
+uint16_t
+initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+		uint32_t dst_addr, uint16_t pkt_data_len);
+
+int
+generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
+		struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr,
+		uint8_t ipv4, struct udp_hdr *udp_hdr, int nb_pkt_per_burst);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* PACKET_BURST_GENERATOR_H_ */
diff --git a/app/test/test.h b/app/test/test.h
index 1945d29..7213e1a 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -94,6 +94,7 @@ int test_pmd_ring(void);
 int test_ivshmem(void);
 int test_kvargs(void);
 int test_devargs(void);
+int test_link_bonding(void);
 
 int test_pci_run;
 
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
new file mode 100644
index 0000000..461d132
--- /dev/null
+++ b/app/test/test_link_bonding.c
@@ -0,0 +1,3943 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_memory.h>
+#include <rte_bond.h>
+
+#include "virtual_pmd.h"
+#include "packet_burst_generator.h"
+
+#include "test.h"
+
+#define TEST_MAX_NUMBER_OF_PORTS (16)
+
+#define RX_RING_SIZE 128
+#define RX_FREE_THRESH 32
+#define RX_PTHRESH 8
+#define RX_HTHRESH 8
+#define RX_WTHRESH 0
+
+#define TX_RING_SIZE 512
+#define TX_FREE_THRESH 32
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+#define TX_RSBIT_THRESH 32
+#define TX_Q_FLAGS (ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOVLANOFFL |\
+	ETH_TXQ_FLAGS_NOXSUMSCTP | ETH_TXQ_FLAGS_NOXSUMUDP | \
+	ETH_TXQ_FLAGS_NOXSUMTCP)
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define MBUF_CACHE_SIZE (250)
+#define BURST_SIZE (32)
+
+#define DEFAULT_MBUF_DATA_SIZE	(2048)
+#define RTE_TEST_RX_DESC_MAX	(2048)
+#define RTE_TEST_TX_DESC_MAX	(2048)
+#define MAX_PKT_BURST			(512)
+#define DEF_PKT_BURST			(16)
+
+#define BONDED_DEV_NAME			("unit_test_bonded_device")
+
+#define INVALID_SOCKET_ID		(-1)
+#define INVALID_PORT_ID			(-1)
+#define INVALID_BONDING_MODE	(-1)
+
+
+uint8_t slave_mac[] = {0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 };
+uint8_t bonded_mac[] = {0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
+
+struct link_bonding_unittest_params {
+	int8_t bonded_port_id;
+	int8_t slave_port_ids[TEST_MAX_NUMBER_OF_PORTS];
+	uint8_t bonded_slave_count;
+	uint8_t bonding_mode;
+
+	uint16_t nb_rx_q;
+	uint16_t nb_tx_q;
+
+	struct rte_mempool *mbuf_pool;
+
+	struct ether_addr *default_slave_mac;
+	struct ether_addr *default_bonded_mac;
+
+	/* Packet Headers */
+	struct ether_hdr *pkt_eth_hdr;
+	struct ipv4_hdr *pkt_ipv4_hdr;
+	struct ipv6_hdr *pkt_ipv6_hdr;
+	struct udp_hdr *pkt_udp_hdr;
+
+};
+
+static struct ipv4_hdr pkt_ipv4_hdr;
+static struct ipv6_hdr pkt_ipv6_hdr;
+static struct udp_hdr pkt_udp_hdr;
+
+static struct link_bonding_unittest_params default_params  = {
+	.bonded_port_id = -1,
+	.slave_port_ids = { 0 },
+	.bonded_slave_count = 0,
+	.bonding_mode = BONDING_MODE_ROUND_ROBIN,
+
+	.nb_rx_q = 1,
+	.nb_tx_q = 1,
+
+	.mbuf_pool = NULL,
+
+	.default_slave_mac = (struct ether_addr *)slave_mac,
+	.default_bonded_mac = (struct ether_addr *)bonded_mac,
+
+	.pkt_eth_hdr = NULL,
+	.pkt_ipv4_hdr = &pkt_ipv4_hdr,
+	.pkt_ipv6_hdr = &pkt_ipv6_hdr,
+	.pkt_udp_hdr = &pkt_udp_hdr
+
+};
+
+static struct link_bonding_unittest_params *test_params = &default_params;
+
+static uint8_t src_mac[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
+static uint8_t dst_mac_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
+static uint8_t dst_mac_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAB };
+
+static uint32_t src_addr = IPV4_ADDR(192, 168, 1, 98);
+static uint32_t dst_addr_0 = IPV4_ADDR(192, 168, 1, 98);
+static uint32_t dst_addr_1 = IPV4_ADDR(193, 166, 10, 97);
+
+static uint8_t src_ipv6_addr[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA  };
+static uint8_t dst_ipv6_addr_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA,  0xFF, 0xAA , 0xFF, 0xAA, 0xFF, 0xAA  };
+static uint8_t dst_ipv6_addr_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA , 0xFF, 0xAB  };
+
+static uint16_t src_port = 1024;
+static uint16_t dst_port_0 = 1024;
+static uint16_t dst_port_1 = 2024;
+
+static uint16_t vlan_id = 0x100;
+
+struct rte_eth_rxmode rx_mode = {
+	.max_rx_pkt_len = ETHER_MAX_LEN, /**< Default maximum frame length. */
+	.split_hdr_size = 0,
+	.header_split   = 0, /**< Header Split disabled. */
+	.hw_ip_checksum = 0, /**< IP checksum offload disabled. */
+	.hw_vlan_filter = 1, /**< VLAN filtering enabled. */
+	.hw_vlan_strip  = 1, /**< VLAN strip enabled. */
+	.hw_vlan_extend = 0, /**< Extended VLAN disabled. */
+	.jumbo_frame    = 0, /**< Jumbo Frame Support disabled. */
+	.hw_strip_crc   = 0, /**< CRC stripping by hardware disabled. */
+};
+
+struct rte_fdir_conf fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.flexbytes_offset = 0x6,
+	.drop_queue = 127,
+};
+
+static struct rte_eth_conf default_pmd_conf = {
+	.rxmode = {
+		.mq_mode = ETH_MQ_RX_NONE,
+		.max_rx_pkt_len = ETHER_MAX_LEN,
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload enabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.lpbk_mode = 0,
+};
+
+static const struct rte_eth_rxconf rx_conf_default = {
+	.rx_thresh = {
+		.pthresh = RX_PTHRESH,
+		.hthresh = RX_HTHRESH,
+		.wthresh = RX_WTHRESH,
+	},
+	.rx_free_thresh = RX_FREE_THRESH,
+	.rx_drop_en = 0,
+};
+
+static struct rte_eth_txconf tx_conf_default = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = TX_FREE_THRESH,
+	.tx_rs_thresh = TX_RSBIT_THRESH,
+	.txq_flags = TX_Q_FLAGS
+
+};
+
+static int
+configure_ethdev(uint8_t port_id, uint8_t start)
+{
+	int q_id;
+
+	if (rte_eth_dev_configure(port_id, test_params->nb_rx_q,
+			test_params->nb_tx_q, &default_pmd_conf) != 0) {
+		goto error;
+	}
+
+	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,
+				rte_eth_dev_socket_id(port_id), &rx_conf_default,
+				test_params->mbuf_pool) < 0) {
+			goto error;
+		}
+	}
+
+	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;
+		}
+	}
+
+	if (start) {
+		if (rte_eth_dev_start(port_id) < 0) {
+			printf("Failed to start device (%d).\n", port_id);
+			goto error;
+		}
+	}
+	return 0;
+
+error:
+	printf("Failed to configure ethdev %d", port_id);
+	return -1;
+}
+
+
+static int
+test_setup(void)
+{
+	int i, retval, nb_mbuf_per_pool;
+	struct ether_addr *mac_addr = (struct ether_addr *)slave_mac;
+
+	/* Allocate ethernet packet header with space for VLAN header */
+	test_params->pkt_eth_hdr = malloc(sizeof(struct ether_hdr) +
+			sizeof(struct vlan_hdr));
+	if (test_params->pkt_eth_hdr == NULL) {
+		printf("ethernet header struct allocation failed!\n");
+		return -1;
+	}
+
+
+	nb_mbuf_per_pool = RTE_TEST_RX_DESC_MAX + DEF_PKT_BURST +
+			RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;
+
+	test_params->mbuf_pool = rte_mempool_create("MBUF_POOL", nb_mbuf_per_pool,
+			MBUF_SIZE, MBUF_CACHE_SIZE, sizeof(struct rte_pktmbuf_pool_private),
+			rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
+			rte_socket_id(), 0);
+	if (test_params->mbuf_pool == NULL) {
+		printf("rte_mempool_create failed\n");
+		return -1;
+	}
+
+	/* Create / Initialize virtual eth devs */
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i;
+
+		test_params->slave_port_ids[i] = virtual_ethdev_create("slave_pmd_1",
+				mac_addr, rte_socket_id());
+		if (test_params->slave_port_ids[i] < 0) {
+			printf("Failed to create virtual pmd eth device.\n");
+			return -1;
+		}
+
+		retval = configure_ethdev(test_params->slave_port_ids[i], 1);
+		if (retval != 0) {
+			printf("Failed to configure virtual pmd eth device.\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+test_create_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	const uint8_t *slaves;
+
+	test_params->bonded_port_id = rte_eth_bond_create(BONDED_DEV_NAME,
+			test_params->bonding_mode, rte_socket_id());
+	if (test_params->bonded_port_id < 0) {
+		printf("\t Failed to create bonded device.\n");
+		return -1;
+	}
+
+	retval = configure_ethdev(test_params->bonded_port_id, 0);
+	if (retval != 0) {
+		printf("Failed to configure bonded pmd eth device.\n");
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count > 0) {
+		printf("Number of slaves is great than expected.\n");
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count > 0) {
+		printf("Number of active slaves is great than expected.\n");
+		return -1;
+	}
+
+
+	if (rte_eth_bond_mode_get(test_params->bonded_port_id) !=
+			test_params->bonding_mode) {
+		printf("Bonded device mode not as expected.\n");
+		return -1;
+
+	}
+
+	return 0;
+}
+
+
+static int
+test_create_bonded_device_with_invalid_params(void)
+{
+	int port_id;
+
+	test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN;
+
+	/* Invalid name */
+	port_id = rte_eth_bond_create(NULL, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	test_params->bonding_mode = INVALID_BONDING_MODE;
+
+	/* Invalid bonding mode */
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN;
+
+	/* Invalid socket id */
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			INVALID_SOCKET_ID);
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_add_slave_to_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	const uint8_t *slaves;
+
+	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;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	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;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count != 0) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				current_slave_count, 0);
+		return -1;
+	}
+
+	test_params->bonded_slave_count++;
+
+	return 0;
+}
+
+static int
+test_add_slave_to_invalid_bonded_device(void)
+{
+	int retval;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_slave_add(test_params->bonded_port_id + 5,
+			test_params->slave_port_ids[test_params->bonded_slave_count]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_slave_add(test_params->slave_port_ids[0],
+			test_params->slave_port_ids[test_params->bonded_slave_count]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+test_remove_slave_from_bonded_device(void)
+{
+	int retval, current_slave_count;
+	struct ether_addr read_mac_addr, *mac_addr;
+	const uint8_t *slaves;
+
+	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;
+	}
+
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	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;
+	}
+
+
+	mac_addr = (struct ether_addr *)slave_mac;
+	mac_addr->addr_bytes[ETHER_ADDR_LEN-1] =
+			test_params->slave_port_ids[test_params->bonded_slave_count-1];
+
+	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;
+	}
+
+	rte_eth_stats_reset(
+			test_params->slave_port_ids[test_params->bonded_slave_count-1]);
+
+	virtual_ethdev_simulate_link_status_interrupt(test_params->bonded_port_id,
+			0);
+
+	test_params->bonded_slave_count--;
+
+	return 0;
+}
+
+static int
+test_remove_slave_from_invalid_bonded_device(void)
+{
+	int retval;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_slave_remove(test_params->bonded_port_id + 5,
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_slave_remove(test_params->slave_port_ids[0],
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_add_already_bonded_slave_to_bonded_device(void)
+{
+	int retval, port_id, current_slave_count;
+	const uint8_t *slaves;
+
+	test_add_slave_to_bonded_device();
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count != 1) {
+		printf("Number of slaves (%d) is not that expected (%d).\n",
+				current_slave_count, 1);
+		return -1;
+	}
+
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id < 0) {
+		printf("Failed to create bonded device.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_slave_add(port_id,
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Added slave (%d) to bonded port (%d) unexpectedly.\n",
+				test_params->slave_port_ids[test_params->bonded_slave_count-1],
+				port_id);
+		return -1;
+	}
+
+	return test_remove_slave_from_bonded_device();
+}
+
+
+static int
+test_get_slaves_from_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	const uint8_t *slaves;
+
+	retval = test_add_slave_to_bonded_device();
+	if (retval != 0)
+		return -1;
+
+	/* Invalid port id */
+	current_slave_count = rte_eth_bond_slaves_get(INVALID_PORT_ID, &slaves);
+	if (current_slave_count >= 0)
+		return -1;
+
+	current_slave_count = rte_eth_bond_active_slaves_get(INVALID_PORT_ID,
+			&slaves);
+	if (current_slave_count >= 0)
+		return -1;
+
+	/* Invalid slaves pointer */
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			NULL);
+	if (current_slave_count >= 0)
+		return -1;
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, NULL);
+	if (current_slave_count >= 0)
+		return -1;
+
+	/* non bonded device*/
+	current_slave_count = rte_eth_bond_slaves_get(
+			test_params->slave_port_ids[0], NULL);
+	if (current_slave_count >= 0)
+		return -1;
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->slave_port_ids[0],	NULL);
+	if (current_slave_count >= 0)
+		return -1;
+
+	retval = test_remove_slave_from_bonded_device();
+	if (retval != 0)
+		return -1;
+
+	return 0;
+}
+
+
+static int
+test_add_remove_multiple_slaves_to_from_bonded_device(void)
+{
+	int i;
+
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		if (test_add_slave_to_bonded_device() != 0)
+			return -1;
+	}
+
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		if (test_remove_slave_from_bonded_device() != 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+static void
+enable_bonded_slaves(void)
+{
+	int i;
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 1);
+	}
+}
+
+static int
+test_start_bonded_device(void)
+{
+	struct rte_eth_link link_status;
+
+	int retval, current_slave_count, current_bonding_mode, primary_port;
+	const uint8_t *slaves;
+
+	/* Add slave to bonded device*/
+	if (test_add_slave_to_bonded_device() != 0)
+		return -1;
+
+	retval = rte_eth_dev_start(test_params->bonded_port_id);
+	if (retval != 0) {
+		printf("Failed to start bonded pmd eth device.\n");
+		return -1;
+	}
+
+	/* Change link status of virtual pmd so it will be added to the active
+	 * slave list of the bonded device*/
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[test_params->bonded_slave_count-1], 1);
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of active slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id);
+	if (current_bonding_mode != test_params->bonding_mode) {
+		printf("Bonded device mode (%d) is not expected value (%d).\n",
+				current_bonding_mode, test_params->bonding_mode);
+		return -1;
+
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[0]) {
+		printf("Primary port (%d) is not expected value (%d).\n",
+				primary_port, test_params->slave_port_ids[0]);
+		return -1;
+
+	}
+
+	rte_eth_link_get(test_params->bonded_port_id, &link_status);
+	if (!link_status.link_status) {
+		printf("Bonded port (%d) status (%d) is not expected value (%d).\n",
+				test_params->bonded_port_id, link_status.link_status, 1);
+		return -1;
+
+	}
+
+	return 0;
+}
+
+static int
+test_stop_bonded_device(void)
+{
+	int current_slave_count;
+	const uint8_t *slaves;
+
+	struct rte_eth_link link_status;
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	rte_eth_link_get(test_params->bonded_port_id, &link_status);
+	if (link_status.link_status) {
+		printf("Bonded port (%d) status (%d) is not expected value (%d).\n",
+				test_params->bonded_port_id, link_status.link_status, 0);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count != 0) {
+		printf("Number of active slaves (%d) is not expected value (%d).\n",
+				current_slave_count, 0);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int remove_slaves_and_stop_bonded_device(void)
+{
+	/* Clean up and remove slaves from bonded device */
+	while (test_params->bonded_slave_count > 0) {
+		if (test_remove_slave_from_bonded_device() != 0) {
+			printf("test_remove_slave_from_bonded_device failed\n");
+			return -1;
+		}
+	}
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+	rte_eth_stats_reset(test_params->bonded_port_id);
+	rte_eth_bond_mac_address_reset(test_params->bonded_port_id);
+
+	return 0;
+}
+
+static int
+test_set_bonding_mode(void)
+{
+	int i;
+	int retval, bonding_mode;
+
+	int bonding_modes[] = { BONDING_MODE_ROUND_ROBIN,
+							BONDING_MODE_ACTIVE_BACKUP,
+							BONDING_MODE_BALANCE,
+							BONDING_MODE_BROADCAST };
+
+	/* Test supported link bonding modes */
+	for (i = 0; i < (int)RTE_DIM(bonding_modes);	i++) {
+		/* Invalid port ID */
+		retval = rte_eth_bond_mode_set(INVALID_PORT_ID, bonding_modes[i]);
+		if (retval == 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					INVALID_PORT_ID);
+			return -1;
+		}
+
+		/* Non bonded device */
+		retval = rte_eth_bond_mode_set(test_params->slave_port_ids[0],
+				bonding_modes[i]);
+		if (retval == 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					test_params->slave_port_ids[0]);
+			return -1;
+		}
+
+		retval = rte_eth_bond_mode_set(test_params->bonded_port_id,
+				bonding_modes[i]);
+		if (retval != 0) {
+			printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+					test_params->bonded_port_id, bonding_modes[i]);
+			return -1;
+		}
+
+		bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id);
+		if (bonding_mode != bonding_modes[i]) {
+			printf("Link bonding mode (%d) of port (%d) is not expected value (%d).\n",
+					bonding_mode, test_params->bonded_port_id,
+					bonding_modes[i]);
+			return -1;
+		}
+
+
+		/* Invalid port ID */
+		bonding_mode = rte_eth_bond_mode_get(INVALID_PORT_ID);
+		if (bonding_mode >= 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					INVALID_PORT_ID);
+			return -1;
+		}
+
+
+		/* Non bonded device */
+		bonding_mode = rte_eth_bond_mode_get(test_params->slave_port_ids[0]);
+		if (bonding_mode >= 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					test_params->slave_port_ids[0]);
+			return -1;
+		}
+
+	}
+
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_set_primary_slave(void)
+{
+	int i, j, retval;
+	struct ether_addr read_mac_addr;
+	struct ether_addr *expected_mac_addr;
+
+	/* Add 4 slaves to bonded device */
+	for (i = test_params->bonded_slave_count; i < 4; i++) {
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave to bonded device.\n");
+			return -1;
+		}
+	}
+	retval = rte_eth_bond_mode_set(test_params->bonded_port_id,
+			BONDING_MODE_ROUND_ROBIN);
+	if (retval != 0) {
+		printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+				test_params->bonded_port_id, BONDING_MODE_ROUND_ROBIN);
+		return -1;
+	}
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_primary_set(INVALID_PORT_ID,
+			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) {
+			printf("Failed to set bonded port (%d) primary port to (%d)\n",
+					test_params->bonded_port_id,
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+
+		retval = rte_eth_bond_primary_get(test_params->bonded_port_id);
+		if (retval < 0) {
+			printf("Failed to read primary port from bonded port (%d)\n",
+					test_params->bonded_port_id);
+			return -1;
+		} else if (retval != test_params->slave_port_ids[i]) {
+			printf("Bonded port (%d) primary port (%d) not expected value (%d)\n",
+					test_params->bonded_port_id, retval,
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+
+		/* 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;
+
+		expected_mac_addr = (struct ether_addr *)&slave_mac;
+		expected_mac_addr->addr_bytes[ETHER_ADDR_LEN-1] =
+				test_params->slave_port_ids[i];
+
+		/* Check primary slave MAC */
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(expected_mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("bonded port mac address not set to that of primary port\n");
+			return -1;
+		}
+
+		/* Check bonded MAC */
+		rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+		if (memcmp(&read_mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("bonded port mac address not set to that of primary port\n");
+			return -1;
+		}
+
+		/* Check other slaves MACs */
+		for (j = 0; j < 4; j++) {
+			if (j != i) {
+				rte_eth_macaddr_get(test_params->slave_port_ids[j],
+						&read_mac_addr);
+				if (memcmp(expected_mac_addr, &read_mac_addr,
+						sizeof(read_mac_addr))) {
+					printf("slave port mac address not set to that of primary port\n");
+					return -1;
+				}
+			}
+		}
+	}
+
+
+	/* Test with none existent port */
+	retval = rte_eth_bond_primary_get(test_params->bonded_port_id + 10);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	/* Test with slave port */
+	retval = rte_eth_bond_primary_get(test_params->slave_port_ids[0]);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	if (remove_slaves_and_stop_bonded_device() != 0)
+		return -1;
+
+	/* No slaves  */
+	retval = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_set_explicit_bonded_mac(void)
+{
+	int i, retval;
+	struct ether_addr read_mac_addr;
+	struct ether_addr *mac_addr;
+
+	uint8_t explicit_bonded_mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01 };
+
+	mac_addr = (struct ether_addr *)explicit_bonded_mac;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_mac_address_set(INVALID_PORT_ID, mac_addr);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_mac_address_set(test_params->slave_port_ids[0],
+			mac_addr);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* NULL MAC address */
+	retval = rte_eth_bond_mac_address_set(test_params->bonded_port_id, NULL);
+	if (retval == 0) {
+		printf("Expected call to failed as NULL MAC specified\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			mac_addr);
+	if (retval != 0) {
+		printf("Failed to set MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* Add 4 slaves to bonded device */
+	for (i = test_params->bonded_slave_count; i < 4; i++) {
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave to bonded device.\n");
+			return -1;
+		}
+	}
+
+	/* Check bonded MAC */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &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;
+	}
+
+	/* Check other slaves MACs */
+	for (i = 0; i < 4; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port mac address not set to that of primary port\n");
+			return -1;
+		}
+	}
+
+	/* test resetting mac address on bonded device */
+	if (rte_eth_bond_mac_address_reset(test_params->bonded_port_id) != 0) {
+		printf("Failed to reset MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+
+		return -1;
+	}
+
+	if (rte_eth_bond_mac_address_reset(test_params->slave_port_ids[0]) == 0) {
+		printf("Reset MAC address on bonded port (%d) unexpectedly\n",
+				test_params->slave_port_ids[1]);
+
+		return -1;
+	}
+
+	/* test resetting mac address on bonded device with no slaves */
+
+	if (remove_slaves_and_stop_bonded_device() != 0)
+		return -1;
+
+	if (rte_eth_bond_mac_address_reset(test_params->bonded_port_id) != 0) {
+		printf("Failed to reset MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+initialize_bonded_device_with_slaves(uint8_t bonding_mode,
+		uint8_t number_of_slaves, uint8_t enable_slave)
+{
+	int retval;
+
+	/* configure bonded device */
+	retval = configure_ethdev(test_params->bonded_port_id, 0);
+	if (retval != 0) {
+		printf("Failed to configure bonding port (%d) in mode %d with (%d) slaves.\n",
+				test_params->bonded_port_id, bonding_mode, number_of_slaves);
+		return -1;
+	}
+
+	while (number_of_slaves > test_params->bonded_slave_count) {
+		/* Add slaves to bonded device */
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave (%d to  bonding port (%d).\n",
+					test_params->bonded_slave_count - 1,
+					test_params->bonded_port_id);
+			return -1;
+		}
+	}
+
+	/* Set link bonding mode  */
+	retval = rte_eth_bond_mode_set(test_params->bonded_port_id, bonding_mode);
+	if (retval != 0) {
+		printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+				test_params->bonded_port_id, bonding_mode);
+		return -1;
+	}
+
+	retval = rte_eth_dev_start(test_params->bonded_port_id);
+	if (retval != 0) {
+		printf("Failed to start bonded pmd eth device.\n");
+		return -1;
+	}
+
+	if (enable_slave)
+		enable_bonded_slaves();
+
+	return 0;
+}
+
+static int
+test_adding_slave_after_bonded_device_started(void)
+{
+	int i;
+
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 0) !=
+			0)
+		return -1;
+
+	/* Enabled slave devices */
+	for (i = 0; i < test_params->bonded_slave_count + 1; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				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_params->bonded_slave_count++;
+
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+generate_test_burst(struct rte_mbuf **pkts_burst, uint16_t burst_size,
+		uint8_t vlan, uint8_t ipv4, uint8_t toggle_dst_mac,
+		uint8_t toggle_ip_addr, uint8_t toggle_udp_port)
+{
+	uint16_t pktlen, generated_burst_size;
+	void *ip_hdr;
+
+	if (toggle_dst_mac)
+		initialize_eth_header(test_params->pkt_eth_hdr,
+				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
+				vlan, vlan_id);
+	else
+		initialize_eth_header(test_params->pkt_eth_hdr,
+				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+				vlan, vlan_id);
+
+
+	if (toggle_udp_port)
+		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+				dst_port_1, 64);
+	else
+		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+				dst_port_0, 64);
+
+	if (ipv4) {
+		if (toggle_ip_addr)
+			pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+					dst_addr_1, pktlen);
+		else
+			pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+					dst_addr_0, pktlen);
+
+		ip_hdr = test_params->pkt_ipv4_hdr;
+	} else {
+		if (toggle_ip_addr)
+			pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr,
+					(uint8_t *)src_ipv6_addr, (uint8_t *)dst_ipv6_addr_1,
+					pktlen);
+		else
+			pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr,
+					(uint8_t *)src_ipv6_addr, (uint8_t *)dst_ipv6_addr_0,
+					pktlen);
+
+		ip_hdr = test_params->pkt_ipv6_hdr;
+	}
+
+	/* Generate burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, vlan, ip_hdr, ipv4,
+			test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size) {
+		printf("Failed to generate packet burst");
+		return -1;
+	}
+
+	return generated_burst_size;
+}
+
+/** Round Robin Mode Tests */
+
+static int
+test_roundrobin_tx_burst(void)
+{
+	int i, burst_size, nb_tx;
+	struct rte_mbuf *pkt_burst[MAX_PKT_BURST];
+	struct rte_eth_stats port_stats;
+
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 2, 1)
+			!= 0)
+		return -1;
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0) != burst_size)
+		return -1;
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst,
+			burst_size);
+	if (nb_tx != burst_size)
+		return -1;
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (port_stats.opackets !=
+				(uint64_t)burst_size / test_params->bonded_slave_count) {
+			printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+					test_params->bonded_port_id,
+					(unsigned int)port_stats.opackets,
+					burst_size / test_params->bonded_slave_count);
+			return -1;
+		}
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst,
+			burst_size);
+	if (nb_tx != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_roundrobin_rx_burst_on_single_slave(void)
+{
+	struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+
+	struct rte_eth_stats port_stats;
+
+	int i, j, nb_rx, burst_size = 25;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1) !=
+			0)
+		return -1;
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(gen_pkt_burst, burst_size, 0, 1, 0, 0, 0) !=
+			burst_size)
+		return -1;
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		/* Add rx data to slave */
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[0], burst_size);
+
+		/* Call rx burst on bonded device */
+		/* Send burst on bonded port */
+		nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+				MAX_PKT_BURST);
+		if (nb_rx != burst_size) {
+			printf("round-robin rx burst failed");
+			return -1;
+		}
+
+		/* Verify bonded device rx count */
+		rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+		if (port_stats.ipackets != (uint64_t)burst_size) {
+			printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+					test_params->bonded_port_id,
+					(unsigned int)port_stats.ipackets, burst_size);
+			return -1;
+		}
+
+
+		/* Verify bonded slave devices rx count */
+		/* Verify slave ports tx stats */
+		for (j = 0; j < test_params->bonded_slave_count; j++) {
+			rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);
+
+			if (i == j) {
+				if (port_stats.ipackets != (uint64_t)burst_size) {
+					printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+							test_params->slave_port_ids[i],
+							(unsigned int)port_stats.ipackets, burst_size);
+					return -1;
+				}
+			} else {
+				if (port_stats.ipackets != 0) {
+					printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+							test_params->slave_port_ids[i],
+							(unsigned int)port_stats.ipackets, 0);
+					return -1;
+				}
+			}
+
+			/* Reset bonded slaves stats */
+			rte_eth_stats_reset(test_params->slave_port_ids[j]);
+		}
+		/* reset bonded device stats */
+		rte_eth_stats_reset(test_params->bonded_port_id);
+	}
+
+	/* free mbufs */
+	for (i = 0; i < MAX_PKT_BURST; i++) {
+		if (gen_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(gen_pkt_burst[i]);
+
+		if (rx_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(rx_pkt_burst[i]);
+	}
+
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT (3)
+
+static int
+test_roundrobin_rx_burst_on_multiple_slaves(void)
+{
+	struct rte_mbuf *gen_pkt_burst[TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT][MAX_PKT_BURST];
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	int burst_size[TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT] = { 15, 13, 36 };
+	int i, nb_rx;
+
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1) !=
+			0)
+		return -1;
+
+	/* Generate test bursts of packets to transmit */
+	for (i = 0; i < TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size[i], 0, 1, 0, 0,
+				0) != burst_size[i])
+			return -1;
+	}
+
+	/* Add rx data to slaves */
+	for (i = 0; i < TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT; i++) {
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size[i]);
+	}
+
+	/* Call rx burst on bonded device */
+	/* Send burst on bonded port */
+	nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+	if (nb_rx != burst_size[0] + burst_size[1] + burst_size[2]) {
+		printf("round-robin rx burst failed (%d != %d)\n", nb_rx,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size[0] + burst_size[1] +
+			burst_size[2])) {
+		printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.ipackets,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+
+	/* Verify bonded slave devices rx counts */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.ipackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.ipackets, burst_size[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[2]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[2],
+				(unsigned int)port_stats.ipackets, burst_size[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.ipackets != 0) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[3],
+				(unsigned int)port_stats.ipackets, 0);
+		return -1;
+	}
+
+	/* free mbufs */
+	for (i = 0; i < MAX_PKT_BURST; i++) {
+		if (rx_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(rx_pkt_burst[i]);
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_roundrobin_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_2;
+
+	int i, retval;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[2], &expected_mac_addr_2);
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1)
+			!= 0)
+		return -1;
+
+	/* Verify that all MACs are the same as first slave added to bonded dev */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	retval = rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[2]);
+	if (retval != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address has changed to that of primary port without stop/start toggle of bonded device\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagate to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_2, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary port\n",
+				test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_2, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary port\n",
+				test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_roundrobin_verify_promiscuous_enable_disable(void)
+{
+	int i, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1) !=
+			0)
+		return -1;
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(test_params->slave_port_ids[i]);
+		if (promiscuous_en != 1) {
+			printf("slave port (%d) promiscuous mode not enabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_RR_LINK_STATUS_SLAVE_COUNT (4)
+#define TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT (2)
+
+static int
+test_roundrobin_verify_slave_link_status_change_behaviour(void)
+{
+	struct rte_mbuf *tx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_mbuf *gen_pkt_burst[TEST_RR_LINK_STATUS_SLAVE_COUNT][MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+
+	struct rte_eth_stats port_stats;
+	const uint8_t *slaves;
+
+	int i, burst_size, slave_count;
+
+	/* NULL all pointers in array to simplify cleanup */
+	memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst));
+
+	/* Initialize bonded device with TEST_RR_LINK_STATUS_SLAVE_COUNT slaves
+	 * in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN,
+			TEST_RR_LINK_STATUS_SLAVE_COUNT, 1) != 0)
+		return -1;
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != TEST_RR_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of slaves (%d) is not as expected (%d).\n", slave_count,
+				TEST_RR_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != TEST_RR_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, TEST_RR_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	/* Set 2 slaves eth_devs link status to down */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves) != TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT);
+		return -1;
+	}
+
+	burst_size = 21;
+
+	/* Verify that pkts are not sent on slaves with link status down:
+	 *
+	 * 1. Generate test burst of traffic
+	 * 2. Transmit burst on bonded eth_dev
+	 * 3. Verify stats for bonded eth_dev (opackets = burst_size)
+	 * 4. Verify stats for slave eth_devs (s0 = 11, s1 = 0, s2 = 10, s3 = 0)
+	 */
+	if (generate_test_burst(tx_pkt_burst, burst_size, 0, 1, 0, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, tx_pkt_burst,
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != 11) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != 10) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	/* Verify that pkts are not sent on slaves with link status down:
+	 *
+	 * 1. Generate test bursts of traffic
+	 * 2. Add bursts on to virtual eth_devs
+	 * 3. Rx burst on bonded eth_dev, expected (burst_ size *
+	 *    TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT) received
+	 * 4. Verify stats for bonded eth_dev
+	 * 6. Verify stats for slave eth_devs (s0 = 11, s1 = 0, s2 = 10, s3 = 0)
+	 */
+	for (i = 0; i < TEST_RR_LINK_STATUS_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0)
+				!= burst_size) {
+			return -1;
+		}
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size);
+	}
+
+	if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST) != burst_size + burst_size) {
+		printf("rte_eth_rx_burst\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.ipackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* free mbufs */
+	for (i = 0; i < MAX_PKT_BURST; i++) {
+		if (rx_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(rx_pkt_burst[i]);
+
+		if (gen_pkt_burst[1][i] != NULL)
+			rte_pktmbuf_free(gen_pkt_burst[1][i]);
+
+		if (gen_pkt_burst[3][i] != NULL)
+			rte_pktmbuf_free(gen_pkt_burst[1][i]);
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+/** Active Backup Mode Tests */
+
+static int
+test_activebackup_tx_burst(void)
+{
+	int i, retval, pktlen, primary_port, burst_size, generated_burst_size, nb_tx;
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);
+	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+			dst_port_0, 16);
+	pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+			dst_addr_0, pktlen);
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate a burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr,
+			1, test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size)
+		return -1;
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != burst_size)
+		return -1;
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (test_params->slave_port_ids[i] == primary_port) {
+			if (port_stats.opackets != (uint64_t)burst_size) {
+				printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+						test_params->bonded_port_id,
+						(unsigned int)port_stats.opackets,
+						burst_size / test_params->bonded_slave_count);
+				return -1;
+			}
+		} else {
+			if (port_stats.opackets != 0) {
+				printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+						test_params->bonded_port_id,
+						(unsigned int)port_stats.opackets, 0);
+				return -1;
+			}
+		}
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT (4)
+
+static int
+test_activebackup_rx_burst(void)
+{
+	struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+
+	struct rte_eth_stats port_stats;
+
+	int primary_port;
+
+	int i, j, nb_rx, burst_size = 17;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP,
+			TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT, 1)
+			!= 0)
+		return -1;
+
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port < 0) {
+		printf("failed to get primary slave for bonded port (%d)",
+				test_params->bonded_port_id);
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		/* Generate test bursts of packets to transmit */
+		if (generate_test_burst(&gen_pkt_burst[0], burst_size, 0, 1, 0, 0, 0)
+				!= burst_size) {
+			return -1;
+		}
+
+		/* Add rx data to slave */
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[0], burst_size);
+
+		/* Call rx burst on bonded device */
+		nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0,
+				&rx_pkt_burst[0], MAX_PKT_BURST);
+		if (nb_rx < 0) {
+			printf("rte_eth_rx_burst failed\n");
+			return -1;
+		}
+
+		if (test_params->slave_port_ids[i] == primary_port) {
+			/* Verify bonded device rx count */
+			rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+			if (port_stats.ipackets != (uint64_t)burst_size) {
+				printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+						test_params->bonded_port_id,
+						(unsigned int)port_stats.ipackets, burst_size);
+				return -1;
+			}
+
+			/* Verify bonded slave devices rx count */
+			for (j = 0; j < test_params->bonded_slave_count; j++) {
+				rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);
+				if (i == j) {
+					if (port_stats.ipackets != (uint64_t)burst_size) {
+						printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+								test_params->slave_port_ids[i],
+								(unsigned int)port_stats.ipackets, burst_size);
+						return -1;
+					}
+				} else {
+					if (port_stats.ipackets != 0) {
+						printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+								test_params->slave_port_ids[i],
+								(unsigned int)port_stats.ipackets, 0);
+						return -1;
+					}
+				}
+			}
+		} else {
+			for (j = 0; j < test_params->bonded_slave_count; j++) {
+				rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);
+				if (port_stats.ipackets != 0) {
+					printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+							test_params->slave_port_ids[i],
+							(unsigned int)port_stats.ipackets, 0);
+					return -1;
+				}
+			}
+		}
+
+		/* free mbufs */
+		for (i = 0; i < MAX_PKT_BURST; i++) {
+			if (rx_pkt_burst[i] != NULL) {
+				rte_pktmbuf_free(rx_pkt_burst[i]);
+				rx_pkt_burst[i] = NULL;
+			}
+		}
+
+		/* reset bonded device stats */
+		rte_eth_stats_reset(test_params->bonded_port_id);
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_activebackup_verify_promiscuous_enable_disable(void)
+{
+	int i, primary_port, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP, 4, 1)
+			!= 0)
+		return -1;
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port < 0) {
+		printf("failed to get primary slave for bonded port (%d)",
+				test_params->bonded_port_id);
+	}
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (primary_port == test_params->slave_port_ids[i]) {
+			if (promiscuous_en != 1) {
+				printf("slave port (%d) promiscuous mode not enabled\n",
+						test_params->slave_port_ids[i]);
+				return -1;
+			}
+		} else {
+			if (promiscuous_en != 0) {
+				printf("slave port (%d) promiscuous mode enabled\n",
+						test_params->slave_port_ids[i]);
+				return -1;
+			}
+		}
+
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_activebackup_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1);
+
+	/* Initialize bonded device with 2 slaves in active backup mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP, 2, 1)
+			!= 0)
+		return -1;
+
+	/* Verify that bonded MACs is that of first slave and that the other slave
+	 * MAC hasn't been changed */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	if (rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[1]) != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagated to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of bonded port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of bonded port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_activebackup_verify_slave_link_status_change_failover(void)
+{
+	struct rte_mbuf *pkt_burst[TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT][MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	const uint8_t *slaves;
+
+	int i, j, burst_size, slave_count, primary_port;
+
+	burst_size = 21;
+
+	memset(pkt_burst, 0, sizeof(pkt_burst));
+
+	/* Generate packet burst for testing */
+	if (generate_test_burst(&pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP,
+			TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT, 1)
+			!= 0)
+		return -1;
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != 4) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[0])
+		printf("Primary port not as expected");
+
+	/* Bring 2 slaves down and verify active slave count */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves)
+			!= 2) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 2);
+		return -1;
+	}
+
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 1);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 1);
+
+
+	/* Bring primary port down, verify that active slave count is 3 and primary
+	 *  has changed */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[0], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves)
+			!= 3) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 3);
+		return -1;
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[2])
+		printf("Primary port not as expected");
+
+	/* Verify that pkts are sent on new primary slave */
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[0][0], burst_size)
+			!= burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	/* Generate packet burst for testing */
+
+	for (i = 0; i < TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0) !=
+				burst_size)
+			return -1;
+
+		virtual_ethdev_add_mbufs_to_rx_queue(
+			test_params->slave_port_ids[i], &pkt_burst[i][0], burst_size);
+	}
+
+	if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST) != burst_size) {
+		printf("rte_eth_rx_burst\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.ipackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	/* free mbufs */
+
+	for (i = 0; i < TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(pkt_burst[i][j]);
+				pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+/** Balance Mode Tests */
+
+static int
+test_balance_xmit_policy_configuration(void)
+{
+	int retval;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP,
+			2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	/* Invalid port id */
+	retval = rte_eth_bond_xmit_policy_set(INVALID_PORT_ID,
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Set xmit policy on non bonded device */
+	retval = rte_eth_bond_xmit_policy_set(test_params->slave_port_ids[0],
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+	if (rte_eth_bond_xmit_policy_get(test_params->bonded_port_id) !=
+			BALANCE_XMIT_POLICY_LAYER2) {
+		printf("balance xmit policy not as expected.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER23);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+	if (rte_eth_bond_xmit_policy_get(test_params->bonded_port_id) !=
+			BALANCE_XMIT_POLICY_LAYER23) {
+		printf("balance xmit policy not as expected.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER34);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+	if (rte_eth_bond_xmit_policy_get(test_params->bonded_port_id) !=
+			BALANCE_XMIT_POLICY_LAYER34) {
+		printf("balance xmit policy not as expected.\n");
+		return -1;
+	}
+
+	/* Invalid port id */
+	if (rte_eth_bond_xmit_policy_get(INVALID_PORT_ID) >= 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT (2)
+
+static int
+test_balance_l2_tx_burst(void)
+{
+	struct rte_mbuf *pkts_burst[TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT][MAX_PKT_BURST];
+	int burst_size[TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT] = { 10, 15 };
+
+	uint16_t pktlen;
+
+	int retval, i;
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE,
+			TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);
+	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+			dst_port_0, 16);
+	pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+			dst_addr_0, pktlen);
+
+	/* Generate a burst 1 of packets to transmit */
+	if (generate_packet_burst(test_params->mbuf_pool, &pkts_burst[0][0],
+			test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, 1,
+			test_params->pkt_udp_hdr, burst_size[0]) != burst_size[0])
+		return -1;
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1, 0, 0);
+
+	/* Generate a burst 2 of packets to transmit */
+	if (generate_packet_burst(test_params->mbuf_pool, &pkts_burst[1][0],
+			test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, 1,
+			test_params->pkt_udp_hdr, burst_size[1]) != burst_size[1])
+		return -1;
+
+	/* Send burst 1 on bonded port */
+	for (i = 0; i < TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT; i++) {
+		if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkts_burst[i][0],
+			burst_size[i]) != burst_size[i])
+			return -1;
+	}
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size[0] + burst_size[1])) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				(unsigned int)port_stats.opackets, burst_size[0] + burst_size[1]);
+		return -1;
+	}
+
+
+	/* Verify slave ports tx stats */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.opackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1], (
+						unsigned int)port_stats.opackets, burst_size[1]);
+		return -1;
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkts_burst[0][0],
+			burst_size[0]) != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+balance_l23_tx_burst(uint8_t vlan_enabled, uint8_t ipv4,
+		uint8_t toggle_mac_addr, uint8_t toggle_ip_addr)
+{
+	int retval, i;
+	int burst_size_1, burst_size_2, nb_tx_1, nb_tx_2;
+
+	struct rte_mbuf *pkts_burst_1[MAX_PKT_BURST];
+	struct rte_mbuf *pkts_burst_2[MAX_PKT_BURST];
+
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER23);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+	burst_size_1 = 20;
+	burst_size_2 = 10;
+
+	if (burst_size_1 > MAX_PKT_BURST || burst_size_2 > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkts_burst_1, burst_size_1, vlan_enabled, ipv4,
+			0, 0, 0) != burst_size_1)
+		return -1;
+
+	if (generate_test_burst(pkts_burst_2, burst_size_2, vlan_enabled, ipv4,
+			toggle_mac_addr, toggle_ip_addr, 0) != burst_size_2)
+		return -1;
+
+	/* Send burst 1 on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != burst_size_1)
+		return -1;
+
+	/* Send burst 2 on bonded port */
+	nb_tx_2 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_2,
+			burst_size_2);
+	if (nb_tx_2 != burst_size_2)
+		return -1;
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(nb_tx_1 + nb_tx_2)) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				(unsigned int)port_stats.opackets, nb_tx_1 + nb_tx_2);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_1) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.opackets, nb_tx_1);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_2) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.opackets, nb_tx_2);
+		return -1;
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_l23_tx_burst_ipv4_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(0, 1, 1, 0);
+}
+
+static int
+test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(1, 1, 0, 1);
+}
+
+static int
+test_balance_l23_tx_burst_ipv6_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(0, 0, 0, 1);
+}
+
+static int
+test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(1, 0, 0, 1);
+}
+
+static int
+test_balance_l23_tx_burst_toggle_mac_addr(void)
+{
+	return balance_l23_tx_burst(0, 0, 1, 0);
+}
+
+static int
+balance_l34_tx_burst(uint8_t vlan_enabled, uint8_t ipv4,
+		uint8_t toggle_mac_addr, uint8_t toggle_ip_addr,
+		uint8_t toggle_udp_port)
+{
+	int retval, i;
+	int burst_size_1, burst_size_2, nb_tx_1, nb_tx_2;
+
+	struct rte_mbuf *pkts_burst_1[MAX_PKT_BURST];
+	struct rte_mbuf *pkts_burst_2[MAX_PKT_BURST];
+
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER34);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+	burst_size_1 = 20;
+	burst_size_2 = 10;
+
+	if (burst_size_1 > MAX_PKT_BURST || burst_size_2 > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkts_burst_1, burst_size_1, vlan_enabled, ipv4, 0,
+			0, 0) != burst_size_1)
+		return -1;
+
+	if (generate_test_burst(pkts_burst_2, burst_size_2, vlan_enabled, ipv4,
+			toggle_mac_addr, toggle_ip_addr, toggle_udp_port) != burst_size_2)
+		return -1;
+
+	/* Send burst 1 on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != burst_size_1)
+		return -1;
+
+	/* Send burst 2 on bonded port */
+	nb_tx_2 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_2,
+			burst_size_2);
+	if (nb_tx_2 != burst_size_2)
+		return -1;
+
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(nb_tx_1 + nb_tx_2)) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				(unsigned int)port_stats.opackets, nb_tx_1 + nb_tx_2);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_1) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.opackets, nb_tx_1);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_2) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.opackets, nb_tx_2);
+		return -1;
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_l34_tx_burst_ipv4_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(0, 1, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_ipv4_toggle_udp_port(void)
+{
+	return balance_l34_tx_burst(0, 1, 0, 0, 1);
+}
+
+static int
+test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(1, 1, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_ipv6_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(0, 0, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(1, 0, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_ipv6_toggle_udp_port(void)
+{
+	return balance_l34_tx_burst(0, 0, 0, 0, 1);
+}
+
+#define TEST_BALANCE_RX_BURST_SLAVE_COUNT (3)
+
+static int
+test_balance_rx_burst(void)
+{
+	struct rte_mbuf *gen_pkt_burst[TEST_BALANCE_RX_BURST_SLAVE_COUNT][MAX_PKT_BURST];
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	int burst_size[TEST_BALANCE_RX_BURST_SLAVE_COUNT] = { 10, 5, 30 };
+	int i, j, nb_rx;
+
+	memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 3, 1)
+			!= 0)
+		return -1;
+
+	/* Generate test bursts of packets to transmit */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size[i], 0, 0, 1,
+				0, 0) != burst_size[i])
+			return -1;
+	}
+	/* Add rx data to slaves */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size[i]);
+	}
+
+	/* Call rx burst on bonded device */
+	/* Send burst on bonded port */
+	nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+	if (nb_rx != burst_size[0] + burst_size[1] + burst_size[2]) {
+		printf("balance rx burst failed\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size[0] + burst_size[1] +
+			burst_size[2])) {
+		printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.ipackets,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+
+	/* Verify bonded slave devices rx counts */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.ipackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.ipackets, burst_size[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[2]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[2],
+				(unsigned int)port_stats.ipackets, burst_size[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.ipackets != 0) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[3],
+				(unsigned int)port_stats.ipackets, 0);
+		return -1;
+	}
+
+	/* free mbufs */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (gen_pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(gen_pkt_burst[i][j]);
+				gen_pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_verify_promiscuous_enable_disable(void)
+{
+	int i, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 4, 1) != 0)
+		return -1;
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 1) {
+			printf("slave port (%d) promiscuous mode not enabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1);
+
+	/* Initialize bonded device with 2 slaves in active backup mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 2, 1) != 0)
+		return -1;
+
+	/* Verify that bonded MACs is that of first slave and that the other slave
+	 * MAC hasn't been changed */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	if (rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[1]) != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagated to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of bonded port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of bonded port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_BALANCE_LINK_STATUS_SLAVE_COUNT (4)
+
+static int
+test_balance_verify_slave_link_status_change_behaviour(void)
+{
+	struct rte_mbuf *pkt_burst[TEST_BALANCE_LINK_STATUS_SLAVE_COUNT][MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	const uint8_t *slaves;
+
+	int i, j, burst_size, slave_count;
+
+	memset(pkt_burst, 0, sizeof(pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE,
+			TEST_BALANCE_LINK_STATUS_SLAVE_COUNT, 1) != 0)
+		return -1;
+
+	if (rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER2)) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != TEST_BALANCE_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of slaves (%d) is not as expected (%d).\n", slave_count,
+				TEST_BALANCE_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != TEST_BALANCE_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, TEST_BALANCE_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	/* Set 2 slaves link status to down */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves) != 2) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 2);
+		return -1;
+	}
+
+	/* Send to sets of packet burst and verify that they are balanced across
+	 *  slaves */
+	burst_size = 21;
+
+	if (generate_test_burst(&pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (generate_test_burst(&pkt_burst[1][0], burst_size, 0, 1, 1, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[0][0],
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[1][0],
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->bonded_port_id, (int)port_stats.opackets,
+				burst_size + burst_size);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->slave_port_ids[0], (int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->slave_port_ids[2], (int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	/* verify that all packets get send on primary slave when no other slaves
+	 * are available */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[2], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves) !=
+			1) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 1);
+		return -1;
+	}
+
+	if (generate_test_burst(&pkt_burst[1][0], burst_size, 0, 1, 1, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[1][0],
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size + burst_size +
+			burst_size)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->bonded_port_id, (int)port_stats.opackets,
+				burst_size + burst_size + burst_size);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->slave_port_ids[0], (int)port_stats.opackets,
+				burst_size + burst_size);
+		return -1;
+	}
+
+
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[0], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 1);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[2], 1);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 1);
+
+	for (i = 0; i < TEST_BALANCE_LINK_STATUS_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0) !=
+				burst_size)
+			return -1;
+
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&pkt_burst[i][0], burst_size);
+	}
+
+
+
+	/* Verify that pkts are not received on slaves with link status down */
+
+	rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size * 3)) {
+		printf("(%d) port_stats.ipackets (%d) not as expected (%d)\n",
+				test_params->bonded_port_id, (int)port_stats.ipackets,
+				burst_size * 3);
+		return -1;
+	}
+
+	/* free mbufs allocate for rx testing */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(pkt_burst[i][j]);
+				pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+/** Broadcast Mode Tests */
+
+static int
+test_broadcast_tx_burst(void)
+{
+	int i, pktlen, retval, burst_size, generated_burst_size, nb_tx;
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);
+
+	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+			dst_port_0, 16);
+	pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+			dst_addr_0, pktlen);
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate a burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr,
+			1, test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size)
+		return -1;
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != burst_size * test_params->bonded_slave_count) {
+		printf("Bonded Port (%d) rx burst failed, packets transmitted value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				nb_tx, burst_size);
+		return -1;
+	}
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size *
+			test_params->bonded_slave_count) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+	}
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (port_stats.opackets != (uint64_t)burst_size) {
+			printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+					test_params->bonded_port_id,
+					(unsigned int)port_stats.opackets, burst_size);
+		}
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define BROADCAST_RX_BURST_NUM_OF_SLAVES (3)
+
+static int
+test_broadcast_rx_burst(void)
+{
+	struct rte_mbuf *gen_pkt_burst[BROADCAST_RX_BURST_NUM_OF_SLAVES][MAX_PKT_BURST];
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	int burst_size[BROADCAST_RX_BURST_NUM_OF_SLAVES] = { 10, 5, 30 };
+	int i, j, nb_rx;
+
+	memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST, 3, 1) != 0)
+		return -1;
+
+
+	/* Generate test bursts of packets to transmit */
+	for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size[i], 0, 0, 1, 0,
+				0) != burst_size[i])
+			return -1;
+	}
+
+	/* Add rx data to slave 0 */
+	for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) {
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size[i]);
+	}
+
+
+	/* Call rx burst on bonded device */
+	/* Send burst on bonded port */
+	nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+	if (nb_rx != burst_size[0] + burst_size[1] + burst_size[2]) {
+		printf("round-robin rx burst failed");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size[0] + burst_size[1] +
+			burst_size[2])) {
+		printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.ipackets,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+
+	/* Verify bonded slave devices rx counts */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.ipackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.ipackets, burst_size[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[2]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[2],
+				(unsigned int)port_stats.ipackets,
+				burst_size[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.ipackets != 0) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[3],
+				(unsigned int)port_stats.ipackets, 0);
+		return -1;
+	}
+
+	/* free mbufs allocate for rx testing */
+	for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (gen_pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(gen_pkt_burst[i][j]);
+				gen_pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_broadcast_verify_promiscuous_enable_disable(void)
+{
+	int i, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 4, 1) != 0)
+		return -1;
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 1) {
+			printf("slave port (%d) promiscuous mode not enabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_broadcast_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;
+
+	int i, retval;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[2], &expected_mac_addr_1);
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST, 4, 1) != 0)
+		return -1;
+
+	/* Verify that all MACs are the same as first slave added to bonded
+	 * device */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	retval = rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[2]);
+	if (retval != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address has changed to that of primary port without stop/start toggle of bonded device\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagated to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary port\n",
+				test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_1, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary port\n",
+				test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define BROADCAST_LINK_STATUS_NUM_OF_SLAVES (4)
+static int
+test_broadcast_verify_slave_link_status_change_behaviour(void)
+{
+	struct rte_mbuf *pkt_burst[BROADCAST_LINK_STATUS_NUM_OF_SLAVES][MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	const uint8_t *slaves;
+
+	int i, j, burst_size, slave_count;
+
+	memset(pkt_burst, 0, sizeof(pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST,
+			BROADCAST_LINK_STATUS_NUM_OF_SLAVES, 1) != 0)
+		return -1;
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	/* Set 2 slaves link status to down */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != 2) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 2);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++)
+		rte_eth_stats_reset(test_params->slave_port_ids[i]);
+
+	/* Verify that pkts are not sent on slaves with link status down */
+	burst_size = 21;
+
+	if (generate_test_burst(&pkt_burst[0][0], burst_size, 0, 0, 1, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[0][0],
+			burst_size) != (burst_size * slave_count)) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size * slave_count)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d)\n",
+				test_params->bonded_port_id, (int)port_stats.opackets,
+				burst_size * slave_count);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	for (i = 0; i < BROADCAST_LINK_STATUS_NUM_OF_SLAVES; i++) {
+		if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 0, 1, 0, 0) !=
+				burst_size) {
+			return -1;
+		}
+
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&pkt_burst[i][0], burst_size);
+	}
+
+	/* Verify that pkts are not received on slaves with link status down */
+
+	if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST) !=
+			burst_size + burst_size) {
+		printf("rte_eth_rx_burst\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.ipackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* free mbufs allocate for rx testing */
+	for (i = 0; i < BROADCAST_LINK_STATUS_NUM_OF_SLAVES; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(pkt_burst[i][j]);
+				pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_reconfigure_bonded_device(void)
+{
+	test_params->nb_rx_q = 4;
+	test_params->nb_tx_q = 4;
+
+	if (configure_ethdev(test_params->bonded_port_id, 0)  != 0) {
+		printf("failed to reconfigure bonded device");
+		return -1;
+	}
+
+
+	test_params->nb_rx_q = 2;
+	test_params->nb_tx_q = 2;
+
+	if (configure_ethdev(test_params->bonded_port_id, 0)  != 0) {
+		printf("failed to reconfigure bonded device with less rx/tx queues");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+test_close_bonded_device(void)
+{
+	rte_eth_dev_close(test_params->bonded_port_id);
+	return 0;
+}
+
+static int
+testsuite_teardown(void)
+{
+	if (test_params->pkt_eth_hdr != NULL)
+		free(test_params->pkt_eth_hdr);
+
+	return 0;
+}
+
+struct unittest {
+	int (*test_function)(void);
+	const char *success_msg;
+	const char *fail_msg;
+};
+
+struct unittest_suite {
+	int (*setup_function)(void);
+	int (*teardown_function)(void);
+	struct unittest unittests[];
+};
+
+static struct unittest_suite link_bonding_test_suite  = {
+	.setup_function = test_setup,
+	.teardown_function = testsuite_teardown,
+	.unittests = {
+		{ test_create_bonded_device, "test_create_bonded_device succeeded",
+			"test_create_bonded_device failed" },
+		{ test_create_bonded_device_with_invalid_params,
+			"test_create_bonded_device_with_invalid_params succeeded",
+			"test_create_bonded_device_with_invalid_params failed" },
+		{ test_add_slave_to_bonded_device,
+			"test_add_slave_to_bonded_device succeeded",
+			"test_add_slave_to_bonded_device failed" },
+		{ test_add_slave_to_invalid_bonded_device,
+			"test_add_slave_to_invalid_bonded_device succeeded",
+			"test_add_slave_to_invalid_bonded_device failed" },
+		{ test_remove_slave_from_bonded_device,
+			"test_remove_slave_from_bonded_device succeeded ",
+			"test_remove_slave_from_bonded_device failed" },
+		{ test_remove_slave_from_invalid_bonded_device,
+			"test_remove_slave_from_invalid_bonded_device succeeded",
+			"test_remove_slave_from_invalid_bonded_device failed" },
+		{ test_get_slaves_from_bonded_device,
+			"test_get_slaves_from_bonded_device succeeded",
+			"test_get_slaves_from_bonded_device failed" },
+		{ test_add_already_bonded_slave_to_bonded_device,
+			"test_add_already_bonded_slave_to_bonded_device succeeded",
+			"test_add_already_bonded_slave_to_bonded_device failed" },
+		{ test_add_remove_multiple_slaves_to_from_bonded_device,
+			"test_add_remove_multiple_slaves_to_from_bonded_device succeeded",
+			"test_add_remove_multiple_slaves_to_from_bonded_device failed" },
+		{ test_start_bonded_device,
+			"test_start_bonded_device succeeded",
+			"test_start_bonded_device failed" },
+		{ test_stop_bonded_device,
+			"test_stop_bonded_device succeeded",
+			"test_stop_bonded_device failed" },
+		{ test_set_bonding_mode,
+			"test_set_bonding_mode succeeded",
+			"test_set_bonding_mode failed" },
+		{ test_set_primary_slave,
+			"test_set_primary_slave succeeded",
+			"test_set_primary_slave failed" },
+		{ test_set_explicit_bonded_mac,
+			"test_set_explicit_bonded_mac succeeded",
+			"test_set_explicit_bonded_mac failed" },
+		{ test_adding_slave_after_bonded_device_started,
+			"test_adding_slave_after_bonded_device_started succeeded",
+			"test_adding_slave_after_bonded_device_started failed" },
+		{ test_roundrobin_tx_burst,
+			"test_roundrobin_tx_burst succeeded",
+			"test_roundrobin_tx_burst failed" },
+		{ test_roundrobin_rx_burst_on_single_slave,
+			"test_roundrobin_rx_burst_on_single_slave succeeded",
+			"test_roundrobin_rx_burst_on_single_slave failed" },
+		{ test_roundrobin_rx_burst_on_multiple_slaves,
+			"test_roundrobin_rx_burst_on_multiple_slaves succeeded",
+			"test_roundrobin_rx_burst_on_multiple_slaves failed" },
+		{ test_roundrobin_verify_promiscuous_enable_disable,
+			"test_roundrobin_verify_promiscuous_enable_disable succeeded",
+			"test_roundrobin_verify_promiscuous_enable_disable failed" },
+		{ test_roundrobin_verify_mac_assignment,
+			"test_roundrobin_verify_mac_assignment succeeded",
+			"test_roundrobin_verify_mac_assignment failed" },
+		{ test_roundrobin_verify_slave_link_status_change_behaviour,
+			"test_roundrobin_verify_slave_link_status_change_behaviour succeeded",
+			"test_roundrobin_verify_slave_link_status_change_behaviour failed" },
+		{ test_activebackup_tx_burst,
+			"test_activebackup_tx_burst succeeded",
+			"test_activebackup_tx_burst failed" },
+		{ test_activebackup_rx_burst,
+			"test_activebackup_rx_burst succeeded",
+			"test_activebackup_rx_burst failed" },
+		{ test_activebackup_verify_promiscuous_enable_disable,
+			"test_activebackup_verify_promiscuous_enable_disable succeeded",
+			"test_activebackup_verify_promiscuous_enable_disable failed" },
+		{ test_activebackup_verify_mac_assignment,
+			"test_activebackup_verify_mac_assignment succeeded",
+			"test_activebackup_verify_mac_assignment failed" },
+		{ test_activebackup_verify_slave_link_status_change_failover,
+			"test_activebackup_verify_slave_link_status_change_failover succeeded",
+			"test_activebackup_verify_slave_link_status_change_failover failed" },
+		{ test_balance_xmit_policy_configuration,
+			"test_balance_xmit_policy_configuration succeeded",
+			"test_balance_xmit_policy_configuration failed" },
+		{ test_balance_l2_tx_burst,
+			"test_balance_l2_tx_burst succeeded",
+			"test_balance_l2_tx_burst failed" },
+		{ test_balance_l23_tx_burst_ipv4_toggle_ip_addr,
+			"test_balance_l23_tx_burst_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr,
+			"test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_ipv6_toggle_ip_addr,
+			"test_balance_l23_tx_burst_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr,
+			"test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_toggle_mac_addr,
+			"test_balance_l23_tx_burst_toggle_mac_addr succeeded",
+			"test_balance_l23_tx_burst_toggle_mac_addr failed" },
+		{ test_balance_l34_tx_burst_ipv4_toggle_ip_addr,
+			"test_balance_l34_tx_burst_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_ipv4_toggle_udp_port,
+			"test_balance_l34_tx_burst_ipv4_toggle_udp_port succeeded",
+			"test_balance_l34_tx_burst_ipv4_toggle_udp_port failed" },
+		{ test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr,
+			"test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_ipv6_toggle_ip_addr,
+			"test_balance_l34_tx_burst_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr,
+			"test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_ipv6_toggle_udp_port,
+			"test_balance_l34_tx_burst_ipv6_toggle_udp_port succeeded",
+			"test_balance_l34_tx_burst_ipv6_toggle_udp_port failed" },
+		{ test_balance_rx_burst,
+			"test_balance_rx_burst succeeded",
+			"test_balance_rx_burst failed" },
+		{ test_balance_verify_promiscuous_enable_disable,
+			"test_balance_verify_promiscuous_enable_disable succeeded",
+			"test_balance_verify_promiscuous_enable_disable failed" },
+		{ test_balance_verify_mac_assignment,
+			"test_balance_verify_mac_assignment succeeded",
+			"test_balance_verify_mac_assignment failed" },
+		{ test_balance_verify_slave_link_status_change_behaviour,
+			"test_balance_verify_slave_link_status_change_behaviour succeeded",
+			"test_balance_verify_slave_link_status_change_behaviour failed" },
+		{ test_broadcast_tx_burst,
+			"test_broadcast_tx_burst succeeded",
+			"test_broadcast_tx_burst failed" },
+		{ test_broadcast_rx_burst,
+			"test_broadcast_rx_burst succeeded",
+			"test_broadcast_rx_burst failed" },
+		{ test_broadcast_verify_promiscuous_enable_disable,
+			"test_broadcast_verify_promiscuous_enable_disable succeeded",
+			"test_broadcast_verify_promiscuous_enable_disable failed" },
+		{ test_broadcast_verify_mac_assignment,
+			"test_broadcast_verify_mac_assignment succeeded",
+			"test_broadcast_verify_mac_assignment failed" },
+		{ test_broadcast_verify_slave_link_status_change_behaviour,
+			"test_broadcast_verify_slave_link_status_change_behaviour succeeded",
+			"test_broadcast_verify_slave_link_status_change_behaviour failed" },
+		{ test_reconfigure_bonded_device,
+			"test_reconfigure_bonded_device succeeded",
+			"test_reconfigure_bonded_device failed" },
+		{ test_close_bonded_device,
+			"test_close_bonded_device succeeded",
+			"test_close_bonded_device failed" },
+
+		{ NULL , NULL, NULL } /**< NULL terminate unit test array */
+	}
+};
+
+
+int
+test_link_bonding(void)
+{
+	int i = 0;
+
+	if (link_bonding_test_suite.setup_function) {
+		if (link_bonding_test_suite.setup_function() != 0)
+			return -1;
+	}
+
+	while (link_bonding_test_suite.unittests[i].test_function) {
+		if (link_bonding_test_suite.unittests[i].test_function() == 0) {
+			printf("%s", link_bonding_test_suite.unittests[i].success_msg ?
+					link_bonding_test_suite.unittests[i].success_msg :
+					"unit test succeeded");
+		} else {
+			printf("%s", link_bonding_test_suite.unittests[i].fail_msg ?
+					link_bonding_test_suite.unittests[i].fail_msg :
+					"unit test failed");
+			return -1;
+		}
+		printf("\n");
+		i++;
+	}
+
+	if (link_bonding_test_suite.teardown_function) {
+		if (link_bonding_test_suite.teardown_function() != 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
new file mode 100644
index 0000000..f2ef084
--- /dev/null
+++ b/app/test/virtual_pmd.c
@@ -0,0 +1,574 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_memory.h>
+
+#include "virtual_pmd.h"
+
+#define MAX_PKT_BURST 512
+
+static const char *virtual_ethdev_driver_name = "Virtual PMD";
+
+struct virtual_ethdev_private {
+	struct rte_eth_stats eth_stats;
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST];
+	int rx_pkt_burst_len;
+};
+
+struct virtual_ethdev_queue {
+	int port_id;
+	int queue_id;
+};
+
+static int
+virtual_ethdev_start_success(struct rte_eth_dev *eth_dev __rte_unused)
+{
+	eth_dev->data->dev_started = 1;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev __rte_unused)
+{
+	eth_dev->data->dev_started = 0;
+
+	return -1;
+}
+static void  virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused)
+{
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_started = 0;
+}
+
+static void
+virtual_ethdev_close(struct rte_eth_dev *dev __rte_unused)
+{}
+
+static int
+virtual_ethdev_configure_success(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static int
+virtual_ethdev_configure_fail(struct rte_eth_dev *dev __rte_unused)
+{
+	return -1;
+}
+
+static void
+virtual_ethdev_info_get(struct rte_eth_dev *dev __rte_unused,
+		struct rte_eth_dev_info *dev_info)
+{
+	dev_info->driver_name = virtual_ethdev_driver_name;
+	dev_info->max_mac_addrs = 1;
+
+	dev_info->max_rx_pktlen = (uint32_t)2048;
+
+	dev_info->max_rx_queues = (uint16_t)128;
+	dev_info->max_tx_queues = (uint16_t)512;
+
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static int
+virtual_ethdev_rx_queue_setup_success(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id, uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	struct virtual_ethdev_queue *rx_q;
+
+	rx_q = (struct virtual_ethdev_queue *)rte_zmalloc_socket(NULL,
+			sizeof(struct virtual_ethdev_queue), 0, socket_id);
+
+	if (rx_q == NULL)
+		return -1;
+
+	rx_q->port_id = dev->data->port_id;
+	rx_q->queue_id = rx_queue_id;
+
+	dev->data->rx_queues[rx_queue_id] = rx_q;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_rx_queue_setup_fail(struct rte_eth_dev *dev __rte_unused,
+		uint16_t rx_queue_id __rte_unused, uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	return -1;
+}
+
+static int
+virtual_ethdev_tx_queue_setup_success(struct rte_eth_dev *dev,
+		uint16_t tx_queue_id, uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct virtual_ethdev_queue *tx_q;
+
+	tx_q = (struct virtual_ethdev_queue *)rte_zmalloc_socket(NULL,
+			sizeof(struct virtual_ethdev_queue), 0, socket_id);
+
+	if (tx_q == NULL)
+		return -1;
+
+	tx_q->port_id = dev->data->port_id;
+	tx_q->queue_id = tx_queue_id;
+
+	dev->data->tx_queues[tx_queue_id] = tx_q;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_tx_queue_setup_fail(struct rte_eth_dev *dev __rte_unused,
+		uint16_t tx_queue_id __rte_unused, uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	return -1;
+}
+
+static void
+virtual_ethdev_rx_queue_release(void *q __rte_unused)
+{
+}
+
+static void
+virtual_ethdev_tx_queue_release(void *q __rte_unused)
+{
+}
+
+static int
+virtual_ethdev_link_update_success(struct rte_eth_dev *bonded_eth_dev,
+		int wait_to_complete __rte_unused)
+{
+	if (!bonded_eth_dev->data->dev_started)
+		bonded_eth_dev->data->dev_link.link_status = 0;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_link_update_fail(struct rte_eth_dev *bonded_eth_dev __rte_unused,
+		int wait_to_complete __rte_unused)
+{
+	return -1;
+}
+
+static void
+virtual_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct virtual_ethdev_private *dev_private = dev->data->dev_private;
+
+	if (stats)
+		rte_memcpy(stats, &dev_private->eth_stats, sizeof(*stats));
+}
+
+static void
+virtual_ethdev_stats_reset(struct rte_eth_dev *dev)
+{
+	struct virtual_ethdev_private *dev_private = dev->data->dev_private;
+
+	dev_private->rx_pkt_burst_len = 0;
+
+	/* Reset internal statistics */
+	memset(&dev_private->eth_stats, 0, sizeof(dev_private->eth_stats));
+}
+
+static void
+virtual_ethdev_promiscuous_mode_enable(struct rte_eth_dev *dev __rte_unused)
+{}
+
+static void
+virtual_ethdev_promiscuous_mode_disable(struct rte_eth_dev *dev __rte_unused)
+{}
+
+
+static struct eth_dev_ops virtual_ethdev_default_dev_ops = {
+		.dev_configure = virtual_ethdev_configure_success,
+		.dev_start = virtual_ethdev_start_success,
+		.dev_stop = virtual_ethdev_stop,
+		.dev_close = virtual_ethdev_close,
+		.dev_infos_get = virtual_ethdev_info_get,
+		.rx_queue_setup = virtual_ethdev_rx_queue_setup_success,
+		.tx_queue_setup = virtual_ethdev_tx_queue_setup_success,
+		.rx_queue_release = virtual_ethdev_rx_queue_release,
+		.tx_queue_release = virtual_ethdev_tx_queue_release,
+		.link_update = virtual_ethdev_link_update_success,
+		.stats_get = virtual_ethdev_stats_get,
+		.stats_reset = virtual_ethdev_stats_reset,
+		.promiscuous_enable = virtual_ethdev_promiscuous_mode_enable,
+		.promiscuous_disable = virtual_ethdev_promiscuous_mode_disable
+};
+
+
+void
+virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->dev_start = virtual_ethdev_start_success;
+	else
+		vrtl_eth_dev->dev_ops->dev_start = virtual_ethdev_start_fail;
+
+}
+
+void
+virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->dev_configure = virtual_ethdev_configure_success;
+	else
+		vrtl_eth_dev->dev_ops->dev_configure = virtual_ethdev_configure_fail;
+}
+
+void
+virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->rx_queue_setup =
+				virtual_ethdev_rx_queue_setup_success;
+	else
+		vrtl_eth_dev->dev_ops->rx_queue_setup =
+				virtual_ethdev_rx_queue_setup_fail;
+}
+
+void
+virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->tx_queue_setup =
+				virtual_ethdev_tx_queue_setup_success;
+	else
+		vrtl_eth_dev->dev_ops->tx_queue_setup =
+				virtual_ethdev_tx_queue_setup_fail;
+}
+
+void
+virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->link_update = virtual_ethdev_link_update_success;
+	else
+		vrtl_eth_dev->dev_ops->link_update = virtual_ethdev_link_update_fail;
+}
+
+
+static uint16_t
+virtual_ethdev_rx_burst_success(void *queue __rte_unused,
+							 struct rte_mbuf **bufs,
+							 uint16_t nb_pkts)
+{
+	struct rte_eth_dev *vrtl_eth_dev;
+	struct virtual_ethdev_queue *pq_map;
+	struct virtual_ethdev_private *dev_private;
+
+	int i;
+
+	pq_map = (struct virtual_ethdev_queue *)queue;
+
+	vrtl_eth_dev = &rte_eth_devices[pq_map->port_id];
+
+	dev_private = vrtl_eth_dev->data->dev_private;
+
+	if (dev_private->rx_pkt_burst_len > 0) {
+		if (dev_private->rx_pkt_burst_len < nb_pkts) {
+
+			for (i = 0; i < dev_private->rx_pkt_burst_len; i++) {
+				bufs[i] = dev_private->rx_pkt_burst[i];
+				dev_private->rx_pkt_burst[i] = NULL;
+			}
+
+			dev_private->eth_stats.ipackets = dev_private->rx_pkt_burst_len;
+		}
+		/* reset private burst values */
+		dev_private->rx_pkt_burst_len = 0;
+	}
+
+	return dev_private->eth_stats.ipackets;
+}
+
+static uint16_t
+virtual_ethdev_rx_burst_fail(void *queue __rte_unused,
+							 struct rte_mbuf **bufs __rte_unused,
+							 uint16_t nb_pkts __rte_unused)
+{
+	return 0;
+}
+
+static uint16_t
+virtual_ethdev_tx_burst_success(void *queue,
+							 struct rte_mbuf **bufs __rte_unused,
+							 uint16_t nb_pkts)
+{
+	struct rte_eth_dev *vrtl_eth_dev;
+	struct virtual_ethdev_queue *tx_q;
+	struct virtual_ethdev_private *dev_private;
+	int i;
+
+	tx_q = (struct virtual_ethdev_queue *)queue;
+
+	vrtl_eth_dev = &rte_eth_devices[tx_q->port_id];
+
+	if (vrtl_eth_dev->data->dev_link.link_status) {
+		dev_private = vrtl_eth_dev->data->dev_private;
+		dev_private->eth_stats.opackets += nb_pkts;
+
+		return nb_pkts;
+	}
+
+	/* free packets in burst */
+	for (i = 0; i < nb_pkts; i++) {
+		if (bufs[i] != NULL)
+			rte_pktmbuf_free(bufs[i]);
+
+		bufs[i] = NULL;
+	}
+
+	return 0;
+}
+
+
+static uint16_t
+virtual_ethdev_tx_burst_fail(void *queue __rte_unused,
+		struct rte_mbuf **bufs __rte_unused, uint16_t nb_pkts __rte_unused)
+{
+	return 0;
+}
+
+
+void
+virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_success;
+	else
+		vrtl_eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_fail;
+}
+
+
+void
+virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_success;
+	else
+		vrtl_eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_fail;
+}
+
+
+void
+virtual_ethdev_simulate_link_status_interrupt(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;
+
+	_rte_eth_dev_callback_process(vrtl_eth_dev, RTE_ETH_EVENT_INTR_LSC);
+}
+
+
+
+void
+virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id,
+		struct rte_mbuf **pkt_burst, int burst_length)
+{
+	struct virtual_ethdev_private *dev_private = NULL;
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	int i;
+
+	dev_private = vrtl_eth_dev->data->dev_private;
+
+	for (i = 0; i < burst_length; i++)
+		dev_private->rx_pkt_burst[i] = pkt_burst[i];
+
+	dev_private->rx_pkt_burst_len = burst_length;
+}
+
+static uint8_t
+get_number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; i < RTE_MAX_MEMSEG && ms[i].addr != NULL; i++) {
+		if (sockets < ms[i].socket_id)
+			sockets = ms[i].socket_id;
+	}
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+}
+
+
+int
+virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
+		uint8_t socket_id)
+{
+	struct rte_pci_device *pci_dev = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct eth_driver *eth_drv = NULL;
+	struct rte_pci_driver *pci_drv = NULL;
+	struct eth_dev_ops *dev_ops = NULL;
+	struct rte_pci_id *id_table = NULL;
+	struct virtual_ethdev_private *dev_private = NULL;
+
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (dev_private) data
+	 */
+
+	if (socket_id >= get_number_of_sockets())
+		goto err;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, socket_id);
+	if (pci_dev == NULL)
+		goto err;
+
+	eth_drv = rte_zmalloc_socket(name, sizeof(*eth_drv), 0, socket_id);
+	if (eth_drv == NULL)
+		goto err;
+
+	pci_drv = rte_zmalloc_socket(name, sizeof(*pci_drv), 0, socket_id);
+	if (pci_drv == NULL)
+		goto err;
+
+	dev_ops = rte_zmalloc_socket(name, sizeof(*dev_ops), 0, socket_id);
+	if (dev_ops == NULL)
+		goto err;
+
+	id_table = rte_zmalloc_socket(name, sizeof(*id_table), 0, socket_id);
+	if (id_table == NULL)
+		goto err;
+
+	dev_private = rte_zmalloc_socket(name, sizeof(*dev_private), 0, socket_id);
+	if (dev_private == NULL)
+		goto err;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate();
+	if (eth_dev == NULL)
+		goto err;
+
+	pci_dev->numa_node = socket_id;
+	pci_drv->name = virtual_ethdev_driver_name;
+	pci_drv->id_table = id_table;
+
+	eth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);
+	eth_dev->driver = eth_drv;
+
+	eth_dev->data->nb_rx_queues = (uint16_t)1;
+	eth_dev->data->nb_tx_queues = (uint16_t)1;
+
+	TAILQ_INIT(&(eth_dev->callbacks));
+
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_link.link_speed = ETH_LINK_SPEED_10000;
+	eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX;
+
+	eth_dev->data->mac_addrs = rte_zmalloc(name, ETHER_ADDR_LEN, 0);
+	if (eth_dev->data->mac_addrs == NULL)
+		goto err;
+
+	memcpy(eth_dev->data->mac_addrs, mac_addr,
+			sizeof(*eth_dev->data->mac_addrs));
+	eth_dev->data->mac_addrs->addr_bytes[5] = eth_dev->data->port_id;
+
+	eth_dev->data->dev_started = 0;
+	eth_dev->data->promiscuous = 0;
+	eth_dev->data->scattered_rx = 0;
+	eth_dev->data->all_multicast = 0;
+
+	memset(dev_private, 0, sizeof(*dev_private));
+	eth_dev->data->dev_private = dev_private;
+
+	eth_dev->dev_ops = dev_ops;
+
+	/* Copy default device operation functions */
+	memcpy(eth_dev->dev_ops, &virtual_ethdev_default_dev_ops,
+			sizeof(*eth_dev->dev_ops));
+
+	eth_dev->pci_dev = pci_dev;
+	eth_dev->pci_dev->driver = &eth_drv->pci_drv;
+
+	eth_dev->pci_dev->driver->id_table->device_id = 0xBEEF;
+
+	eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_success;
+	eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_success;
+
+	return eth_dev->data->port_id;
+
+err:
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (pci_drv)
+		rte_free(pci_drv);
+	if (eth_drv)
+		rte_free(eth_drv);
+	if (dev_ops)
+		rte_free(dev_ops);
+	if (id_table)
+		rte_free(id_table);
+	if (dev_private)
+		rte_free(dev_private);
+
+	return -1;
+}
diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h
new file mode 100644
index 0000000..766b6ac
--- /dev/null
+++ b/app/test/virtual_pmd.h
@@ -0,0 +1,74 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VIRTUAL_ETHDEV_H_
+#define __VIRTUAL_ETHDEV_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ether.h>
+
+int virtual_ethdev_init(void);
+
+int virtual_ethdev_create(const char *name, struct ether_addr *mac_addr, uint8_t socket_id);
+
+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);
+
+void virtual_ethdev_stop_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_rx_queue_setup_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_link_update_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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VIRTUAL_ETHDEV_H_ */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 1/4] " declan.doherty
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 2/4] Link bonding unit tests, including: - code to generate packet bursts for testing rx and tx functionality of bonded device - virtual/stubbed out ethdev for use as slave ethdev in testing - checkpack fixes declan.doherty
@ 2014-06-04 15:18   ` declan.doherty
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 3/4] Adding link bonding support to testpmd. - Includes the ability to create new bonded devices. - Add /remove bonding slave devices. - Interogate bonded device stats/configuration - Change bonding modes and select balance transmit polices declan.doherty
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 127+ messages in thread
From: declan.doherty @ 2014-06-04 15:18 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

v2 patch additions,
fix for tx burst broadcast, incrementing the reference count on each mbuf by the number of slaves - 1 
add/remove slave behavior chnange to fix primary slave port assignment 
patchcheck code fixes 

Initial release of Link Bonding Library (lib/librte_bond) with support for bonding modes :
 0 - Round Robin
 1 - Active Backup
 2 - Balance l2 / l23 / l34
 3 - Broadcast

patches split:
 1 - library + makefile changes
 2 - Unit test suite, including code to generate packet bursts for
    testing rx and tx functionality of bonded device and a
    virtual/stubbed out ethdev for use as slave ethdev in testing
 3 - Link bonding integration into testpmd, including :
     - Includes the ability to  create new bonded devices.
     - Add /remove bonding slave devices. 
     - Interogate bonded device stats/configuration
     - Change bonding modes and select balance transmit polices
 4 - Add Link Bonding Library to Doxygen


 app/test-pmd/cmdline.c            |  570 ++++++
 app/test-pmd/config.c             |    4 +-
 app/test-pmd/parameters.c         |    4 +-
 app/test-pmd/testpmd.c            |   37 +-
 app/test-pmd/testpmd.h            |    2 +
 app/test/Makefile                 |    3 +
 app/test/commands.c               |    3 +
 app/test/packet_burst_generator.c |  289 +++
 app/test/packet_burst_generator.h |   78 +
 app/test/test.h                   |    1 +
 app/test/test_link_bonding.c      | 3943 +++++++++++++++++++++++++++++++++++++
 app/test/virtual_pmd.c            |  574 ++++++
 app/test/virtual_pmd.h            |   74 +
 config/common_bsdapp              |    5 +
 config/common_linuxapp            |    5 +
 doc/doxy-api-index.md             |    1 +
 doc/doxy-api.conf                 |    1 +
 lib/Makefile                      |    1 +
 lib/librte_bond/Makefile          |   28 +
 lib/librte_bond/rte_bond.c        | 1682 ++++++++++++++++
 lib/librte_bond/rte_bond.h        |  228 +++
 mk/rte.app.mk                     |    5 +
 22 files changed, 7531 insertions(+), 7 deletions(-)
 create mode 100644 app/test/packet_burst_generator.c
 create mode 100644 app/test/packet_burst_generator.h
 create mode 100644 app/test/test_link_bonding.c
 create mode 100644 app/test/virtual_pmd.c
 create mode 100644 app/test/virtual_pmd.h
 create mode 100644 lib/librte_bond/Makefile
 create mode 100644 lib/librte_bond/rte_bond.c
 create mode 100644 lib/librte_bond/rte_bond.h

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 1/4] " declan.doherty
@ 2014-06-04 15:18     ` declan.doherty
  2014-06-05 15:15     ` Stephen Hemminger
  2014-06-09 21:11     ` Eric Kinzie
  2 siblings, 0 replies; 127+ messages in thread
From: declan.doherty @ 2014-06-04 15:18 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

- Broadcast TX burst broadcast bug fix
- Add/remove slave behavior fix
- Checkpatch fixes

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 config/common_bsdapp       |    5 +
 config/common_linuxapp     |    5 +
 lib/Makefile               |    1 +
 lib/librte_bond/Makefile   |   28 +
 lib/librte_bond/rte_bond.c | 1682 ++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_bond/rte_bond.h |  228 ++++++
 mk/rte.app.mk              |    5 +
 7 files changed, 1954 insertions(+)
 create mode 100644 lib/librte_bond/Makefile
 create mode 100644 lib/librte_bond/rte_bond.c
 create mode 100644 lib/librte_bond/rte_bond.h

diff --git a/config/common_bsdapp b/config/common_bsdapp
index 2cc7b80..53ed8b9 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -187,6 +187,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=y
 
 #
+# Compile link bonding library
+#
+CONFIG_RTE_LIBRTE_BOND=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 62619c6..35b525a 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -211,6 +211,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=n
 
 
+#
+# Compile link bonding library
+#
+CONFIG_RTE_LIBRTE_BOND=y
+
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
 
 #
diff --git a/lib/Makefile b/lib/Makefile
index b92b392..9995ba8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -47,6 +47,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += librte_pmd_pcap
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
+DIRS-$(CONFIG_RTE_LIBRTE_BOND) += librte_bond
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net
diff --git a/lib/librte_bond/Makefile b/lib/librte_bond/Makefile
new file mode 100644
index 0000000..7514378
--- /dev/null
+++ b/lib/librte_bond/Makefile
@@ -0,0 +1,28 @@
+# <COPYRIGHT_TAG>
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_bond.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_BOND) += rte_bond.c
+
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_bond.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_BOND) += lib/librte_mbuf lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_BOND) += lib/librte_malloc
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_bond/rte_bond.c b/lib/librte_bond/rte_bond.c
new file mode 100644
index 0000000..c079b89
--- /dev/null
+++ b/lib/librte_bond/rte_bond.c
@@ -0,0 +1,1682 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <linux/binfmts.h>
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_memory.h>
+#include <rte_string_fns.h>
+#include <rte_cycles.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_etheraddr.h>
+
+#include "rte_bond.h"
+
+static const char *driver_name = "Link Bonding PMD";
+
+/** Port Queue Mapping Structure */
+struct bond_rx_queue {
+	int queue_id;							/**< Queue Id */
+	struct bond_dev_private *dev_private;	/**< Reference to eth_dev private
+												 structure */
+
+	uint16_t nb_rx_desc;					/**< Number of RX descriptors
+												 available for the queue */
+	struct rte_eth_rxconf rx_conf;			/**< Copy of RX configuration
+												 structure for queue */
+	struct rte_mempool *mb_pool;			/**< Reference to mbuf pool to use
+												 for RX queue */
+};
+
+struct bond_tx_queue {
+	int queue_id;							/**< Queue Id */
+	struct bond_dev_private *dev_private;	/**< Reference to dev private
+												 structure */
+	uint16_t nb_tx_desc;					/**< Number of TX descriptors
+												 available for the queue */
+	struct rte_eth_txconf tx_conf;			/**< 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 */
+};
+
+/** Link Bonding PMD device private configuration Structure */
+struct bond_dev_private {
+	uint8_t mode;						/**< Link Bonding Mode */
+	uint8_t primary_port;				/**< Primary Slave Port */
+	uint8_t balance_xmit_policy;		/**< Transmit policy - l2 / l23 / l34
+											 for operation in balance mode */
+	uint8_t user_defined_mac;			/**< Flag for whether MAC address is
+											 user defined or not */
+	uint8_t promiscuous_en;				/**< Enabled/disable promiscuous mode on
+											slave devices */
+	uint8_t link_props_set;				/**< Bonded eth_dev link properties set*/
+
+	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_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];
+};
+
+static struct slave_conf *
+slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id);
+
+static int
+valid_bonded_ethdev(struct rte_eth_dev *eth_dev)
+{
+	size_t len;
+
+	/* Check valid pointer */
+	if (eth_dev->driver->pci_drv.name == NULL || driver_name == NULL)
+		return -1;
+
+	/* Check string lengths are equal */
+	len = strlen(driver_name);
+	if (strlen(eth_dev->driver->pci_drv.name) != len)
+		return -1;
+
+	/* Compare strings */
+	return strncmp(eth_dev->driver->pci_drv.name, driver_name, len);
+}
+
+static int
+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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+valid_bonded_port_id(uint8_t port_id)
+{
+	/* Verify that port id's are valid */
+	if (valid_port_id(port_id))
+		return -1;
+
+	/* 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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+valid_slave_port_id(uint8_t port_id)
+{
+	/* Verify that port id's are valid */
+	if (valid_port_id(port_id))
+		return -1;
+
+	/* Verify that port_id refers to a non bonded port */
+	if (!valid_bonded_ethdev(&rte_eth_devices[port_id]))
+		return -1;
+
+	return 0;
+}
+
+
+static uint16_t
+bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+
+	uint16_t num_rx_slave = 0;
+	uint16_t num_rx_total = 0;
+
+	int i;
+
+	/* Cast to structure, containing bonded device's port id and queue id */
+	struct bond_rx_queue *bd_rx_q = (struct bond_rx_queue *)queue;
+
+	internals = bd_rx_q->dev_private;
+
+	switch (internals->mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BROADCAST:
+	case BONDING_MODE_BALANCE:
+		for (i = 0; i < internals->active_slave_count; i++) {
+			/* Offset of pointer to *bufs increases as packets are received
+			 * from other slaves */
+			num_rx_slave = rte_eth_rx_burst(internals->active_slaves[i],
+					bd_rx_q->queue_id, bufs + num_rx_total, nb_pkts);
+			if (num_rx_slave)
+				num_rx_total += num_rx_slave;
+		}
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+		num_rx_slave = rte_eth_rx_burst(internals->primary_port,
+				bd_rx_q->queue_id, bufs, nb_pkts);
+		if (num_rx_slave)
+			num_rx_total = num_rx_slave;
+		break;
+	}
+	return num_rx_total;
+}
+
+
+static uint16_t
+bond_ethdev_tx_round_robin(void *queue, struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	struct bond_dev_private *dev_private;
+	struct bond_tx_queue *bd_tx_q;
+
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS][nb_pkts];
+	uint16_t slave_nb_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	static int last_slave_idx = -1;
+	int i, slave_idx;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	dev_private = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = dev_private->active_slave_count;
+	memcpy(slaves, dev_private->active_slaves,
+			sizeof(dev_private->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return num_tx_total;
+
+	/* Populate slaves mbuf with which packets are to be sent on it  */
+	for (i = 0; i < nb_pkts; i++) {
+		slave_idx = i % num_of_slaves;
+		slave_bufs[slave_idx][(slave_nb_pkts[slave_idx])++] = bufs[i];
+	}
+
+	/* calculate the next slave to transmit on based on the last slave idx used
+	 * in the last call to bond_ethdev_tx_burst_round_robin */
+	slave_idx = last_slave_idx + 1;
+
+	/* Send packet burst on each slave device */
+	for (i = 0; i < num_of_slaves; i++) {
+		slave_idx = (slave_idx + i) % num_of_slaves;
+
+		if (slave_nb_pkts[i] > 0) {
+			num_tx_total += rte_eth_tx_burst(slaves[slave_idx],
+					bd_tx_q->queue_id, slave_bufs[i], slave_nb_pkts[i]);
+		}
+	}
+
+	last_slave_idx = slave_idx;
+
+	return num_tx_total;
+}
+
+static uint16_t bond_ethdev_tx_active_backup(void *queue,
+		struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	if (internals->active_slave_count < 1)
+		return 0;
+
+	return rte_eth_tx_burst(internals->primary_port, bd_tx_q->queue_id,
+			bufs, nb_pkts);
+}
+
+
+static inline uint16_t
+ether_hash(struct ether_hdr *eth_hdr)
+{
+	uint16_t *word_src_addr = (uint16_t *)eth_hdr->s_addr.addr_bytes;
+	uint16_t *word_dst_addr = (uint16_t *)eth_hdr->d_addr.addr_bytes;
+
+	return (word_src_addr[0] ^ word_dst_addr[0]) ^
+			(word_src_addr[1] ^ word_dst_addr[1]) ^
+			(word_src_addr[2] ^ word_dst_addr[2]);
+}
+
+static inline uint32_t
+ipv4_hash(struct ipv4_hdr *ipv4_hdr)
+{
+	return (ipv4_hdr->src_addr ^ ipv4_hdr->dst_addr);
+}
+
+static inline uint32_t
+ipv6_hash(struct ipv6_hdr *ipv6_hdr)
+{
+	uint32_t *word_src_addr = (uint32_t *)&(ipv6_hdr->src_addr[0]);
+	uint32_t *word_dst_addr = (uint32_t *)&(ipv6_hdr->dst_addr[0]);
+
+	return (word_src_addr[0] ^ word_dst_addr[0]) ^
+			(word_src_addr[1] ^ word_dst_addr[1]) ^
+			(word_src_addr[2] ^ word_dst_addr[2]) ^
+			(word_src_addr[3] ^ word_dst_addr[3]);
+}
+
+static uint32_t
+udp_hash(struct udp_hdr *hdr)
+{
+	return hdr->src_port ^ hdr->dst_port;
+}
+
+static inline uint16_t
+xmit_slave_hash(const struct rte_mbuf *buf, uint8_t slave_count, uint8_t policy)
+{
+	struct ether_hdr *eth_hdr;
+	struct udp_hdr *udp_hdr;
+	size_t eth_offset = 0;
+	uint32_t hash = 0;
+
+	if (slave_count == 1)
+		return 0;
+
+	switch (policy) {
+	case BALANCE_XMIT_POLICY_LAYER2:
+		eth_hdr = (struct ether_hdr *)buf->pkt.data;
+
+		hash = ether_hash(eth_hdr);
+		hash ^= hash >> 8;
+		return hash % slave_count;
+
+
+	case BALANCE_XMIT_POLICY_LAYER23:
+		eth_hdr = (struct ether_hdr *)buf->pkt.data;
+
+		if (buf->ol_flags & PKT_RX_VLAN_PKT)
+			eth_offset = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_offset = sizeof(struct ether_hdr);
+
+		if (buf->ol_flags & PKT_RX_IPV4_HDR) {
+			struct ipv4_hdr *ipv4_hdr;
+			ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(buf,
+					unsigned char *) + eth_offset);
+
+			hash = ether_hash(eth_hdr) ^ ipv4_hash(ipv4_hdr);
+
+		} else {
+			struct ipv6_hdr *ipv6_hdr;
+
+			ipv6_hdr = (struct ipv6_hdr *)(rte_pktmbuf_mtod(buf,
+					unsigned char *) + eth_offset);
+
+			hash = ether_hash(eth_hdr) ^ ipv6_hash(ipv6_hdr);
+		}
+		break;
+
+	case BALANCE_XMIT_POLICY_LAYER34:
+		if (buf->ol_flags & PKT_RX_VLAN_PKT)
+			eth_offset = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_offset = sizeof(struct ether_hdr);
+
+		if (buf->ol_flags & PKT_RX_IPV4_HDR) {
+			struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)
+					(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset);
+
+			if (ipv4_hdr->next_proto_id == IPPROTO_UDP) {
+				udp_hdr = (struct udp_hdr *)
+						(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset +
+								sizeof(struct ipv4_hdr));
+				hash = ipv4_hash(ipv4_hdr) ^ udp_hash(udp_hdr);
+			} else {
+				hash = ipv4_hash(ipv4_hdr);
+			}
+		} else {
+			struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)
+					(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset);
+
+			if (ipv6_hdr->proto == IPPROTO_UDP) {
+				udp_hdr = (struct udp_hdr *)
+						(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset +
+								sizeof(struct ipv6_hdr));
+				hash = ipv6_hash(ipv6_hdr) ^ udp_hash(udp_hdr);
+			} else {
+				hash = ipv6_hash(ipv6_hdr);
+			}
+		}
+		break;
+	}
+
+	hash ^= hash >> 16;
+	hash ^= hash >> 8;
+
+	return hash % slave_count;
+}
+
+static uint16_t
+bond_ethdev_tx_balance(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	int i, op_slave_id;
+
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS][nb_pkts];
+	uint16_t slave_nb_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = internals->active_slave_count;
+	memcpy(slaves, internals->active_slaves,
+			sizeof(internals->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return num_tx_total;
+
+
+	/* Populate slaves mbuf with the packets which are to be sent on it  */
+	for (i = 0; i < nb_pkts; i++) {
+		/* Select output slave using hash based on xmit policy */
+		op_slave_id = xmit_slave_hash(bufs[i], num_of_slaves,
+				internals->balance_xmit_policy);
+
+		/* Populate slave mbuf arrays with mbufs for that slave */
+		slave_bufs[op_slave_id][slave_nb_pkts[op_slave_id]++] = bufs[i];
+	}
+
+	/* Send packet burst on each slave device */
+	for (i = 0; i < num_of_slaves; i++) {
+		if (slave_nb_pkts[i] > 0) {
+			num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
+					slave_bufs[i], slave_nb_pkts[i]);
+		}
+	}
+
+	return num_tx_total;
+}
+
+static uint16_t
+bond_ethdev_tx_burst_broadcast(void *queue, struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	int i;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = internals->active_slave_count;
+	memcpy(slaves, internals->active_slaves,
+			sizeof(internals->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return 0;
+
+	/* Increment reference count on mbufs */
+	for (i = 0; i < nb_pkts; i++)
+		rte_mbuf_refcnt_update(bufs[i], num_of_slaves - 1);
+
+	/* Transmit burst on each active slave */
+	for (i = 0; i < num_of_slaves; i++)
+		num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
+				bufs, nb_pkts);
+
+	return num_tx_total;
+}
+
+static void
+link_properties_set(struct rte_eth_dev *bonded_eth_dev,
+		struct rte_eth_link *slave_dev_link)
+{
+	struct rte_eth_link *bonded_dev_link = &bonded_eth_dev->data->dev_link;
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	if (slave_dev_link->link_status &&
+		bonded_eth_dev->data->dev_started) {
+		bonded_dev_link->link_duplex = slave_dev_link->link_duplex;
+		bonded_dev_link->link_speed = slave_dev_link->link_speed;
+
+		internals->link_props_set = 1;
+	}
+}
+
+static void
+link_properties_reset(struct rte_eth_dev *bonded_eth_dev)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	memset(&(bonded_eth_dev->data->dev_link), 0,
+			sizeof(bonded_eth_dev->data->dev_link));
+
+	internals->link_props_set = 0;
+}
+
+static int
+link_properties_valid(struct rte_eth_link *bonded_dev_link,
+		struct rte_eth_link *slave_dev_link)
+{
+	if (bonded_dev_link->link_duplex != slave_dev_link->link_duplex ||
+		bonded_dev_link->link_speed !=  slave_dev_link->link_speed)
+		return -1;
+
+	return 0;
+}
+
+static int
+mac_address_set(struct rte_eth_dev *eth_dev, struct ether_addr *new_mac_addr)
+{
+	struct ether_addr *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__);
+		return -1;
+	}
+
+	if (new_mac_addr == NULL) {
+		RTE_LOG(ERR, PMD, "%s: NULL pointer MAC specified\n", __func__);
+		return -1;
+	}
+
+	/* 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));
+
+	return 0;
+}
+
+static int
+mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+	int i;
+
+	/* Update slave devices MAC addresses */
+	if (internals->slave_count < 1)
+		return -1;
+
+	switch (internals->mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+	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]],
+					bonded_eth_dev->data->mac_addrs)) {
+				RTE_LOG(ERR, PMD,
+						"%s: Failed to update port Id %d MAC address\n",
+						__func__, internals->slaves[i]);
+				return -1;
+			}
+		}
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		for (i = 0; i < internals->slave_count; i++) {
+			if (internals->slaves[i] == internals->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->primary_port);
+				}
+			} 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]);
+
+
+					return -1;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+static int
+bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
+{
+	struct bond_dev_private *internals;
+
+	internals = eth_dev->data->dev_private;
+
+	switch (mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_round_robin;
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_active_backup;
+		break;
+	case BONDING_MODE_BALANCE:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_balance;
+		break;
+	case BONDING_MODE_BROADCAST:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_broadcast;
+		break;
+	default:
+		return -1;
+	}
+	internals->mode = mode;
+
+	return 0;
+}
+
+static int
+slave_configure(struct rte_eth_dev *bonded_eth_dev,
+		struct rte_eth_dev *slave_eth_dev)
+{
+	struct bond_rx_queue *bd_rx_q;
+	struct bond_tx_queue *bd_tx_q;
+
+	int 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;
+
+	if (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;
+	}
+
+	/* 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,
+				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;
+		}
+	}
+
+	/* Setup Tx Queues */
+	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,
+				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;
+		}
+	}
+
+	/* 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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static 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;
+}
+
+static void
+slave_config_clear(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) {
+			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]));
+		}
+	}
+}
+
+static void
+slave_config_store(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];
+
+	presisted_slave_conf->port_id = slave_eth_dev->data->port_id;
+
+	memcpy(&(presisted_slave_conf->mac_addr), slave_eth_dev->data->mac_addrs,
+			sizeof(struct ether_addr));
+}
+
+static void
+bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev);
+
+static int
+bond_ethdev_start(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals;
+	int i;
+
+	/* 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);
+		return -1;
+	}
+
+	eth_dev->data->dev_link.link_status = 1;
+	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__);
+		return -1;
+	}
+
+	if (internals->user_defined_mac == 0) {
+		struct slave_conf *conf = slave_config_get(internals,
+				internals->primary_port);
+
+		if (mac_address_set(eth_dev, &(conf->mac_addr)) != 0) {
+			RTE_LOG(ERR, PMD,
+					"bonded port (%d) failed to update mac address",
+					eth_dev->data->port_id);
+			return -1;
+		}
+	}
+
+	/* Update all slave devices MACs*/
+	if (mac_address_slaves_update(eth_dev) != 0)
+		return -1;
+
+	/* If bonded device is configure in promiscuous mode then re-apply config */
+	if (internals->promiscuous_en)
+		bond_ethdev_promiscuous_enable(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)",
+					eth_dev->data->port_id, internals->slaves[i]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static void
+bond_ethdev_stop(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals = eth_dev->data->dev_private;
+
+	internals->active_slave_count = 0;
+
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_started = 0;
+}
+
+static void
+bond_ethdev_close(struct rte_eth_dev *dev __rte_unused)
+{
+}
+
+static int
+bond_ethdev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static void
+bond_ethdev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
+{
+	dev_info->driver_name = driver_name;
+	dev_info->max_mac_addrs = 1;
+
+	dev_info->max_rx_pktlen = (uint32_t)2048;
+
+	dev_info->max_rx_queues = (uint16_t)128;
+	dev_info->max_tx_queues = (uint16_t)512;
+
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = dev->pci_dev;
+}
+
+static int
+bond_ethdev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc, unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool)
+{
+	struct bond_rx_queue *bd_rx_q = (struct bond_rx_queue *)
+			rte_zmalloc_socket(NULL, sizeof(struct bond_rx_queue),
+					0, dev->pci_dev->numa_node);
+	if (bd_rx_q == NULL)
+		return -1;
+
+	bd_rx_q->queue_id = rx_queue_id;
+	bd_rx_q->dev_private = dev->data->dev_private;
+
+	bd_rx_q->nb_rx_desc = nb_rx_desc;
+
+	memcpy(&(bd_rx_q->rx_conf), rx_conf, sizeof(struct rte_eth_rxconf));
+	bd_rx_q->mb_pool = mb_pool;
+
+	dev->data->rx_queues[rx_queue_id] = bd_rx_q;
+
+	return 0;
+}
+
+static int
+bond_ethdev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc, unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf)
+{
+	struct bond_tx_queue *bd_tx_q  = (struct bond_tx_queue *)
+			rte_zmalloc_socket(NULL, sizeof(struct bond_tx_queue),
+					0, dev->pci_dev->numa_node);
+
+	if (bd_tx_q == NULL)
+			return -1;
+
+	bd_tx_q->queue_id = tx_queue_id;
+	bd_tx_q->dev_private = dev->data->dev_private;
+
+	bd_tx_q->nb_tx_desc = nb_tx_desc;
+	memcpy(&(bd_tx_q->tx_conf), tx_conf, sizeof(bd_tx_q->tx_conf));
+
+	dev->data->tx_queues[tx_queue_id] = bd_tx_q;
+
+	return 0;
+}
+
+static void
+bond_ethdev_rx_queue_release(void *queue)
+{
+	if (queue == NULL)
+		return;
+
+	rte_free(queue);
+}
+
+static void
+bond_ethdev_tx_queue_release(void *queue)
+{
+	if (queue == NULL)
+		return;
+
+	rte_free(queue);
+}
+
+
+static int
+bond_ethdev_link_update(struct rte_eth_dev *bonded_eth_dev,
+		int wait_to_complete)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	if (!bonded_eth_dev->data->dev_started ||
+		internals->active_slave_count == 0) {
+		bonded_eth_dev->data->dev_link.link_status = 0;
+		return 0;
+	} else {
+		struct rte_eth_dev *slave_eth_dev;
+		int i, link_up = 0;
+
+		for (i = 0; i < internals->active_slave_count; i++) {
+			slave_eth_dev = &rte_eth_devices[internals->active_slaves[i]];
+
+			(*slave_eth_dev->dev_ops->link_update)(slave_eth_dev,
+					wait_to_complete);
+			if (slave_eth_dev->data->dev_link.link_status == 1) {
+				link_up = 1;
+				break;
+			}
+		}
+
+		bonded_eth_dev->data->dev_link.link_status = link_up;
+	}
+
+	return 0;
+}
+
+static void
+bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	struct rte_eth_stats slave_stats;
+
+	int i;
+
+	/* clear bonded stats before populating from slaves */
+	memset(stats, 0, sizeof(*stats));
+
+	for (i = 0; i < internals->slave_count; i++) {
+		rte_eth_stats_get(internals->slaves[i], &slave_stats);
+
+		stats->ipackets += slave_stats.ipackets;
+		stats->opackets += slave_stats.opackets;
+		stats->ibytes += slave_stats.ibytes;
+		stats->obytes += slave_stats.obytes;
+		stats->ierrors += slave_stats.ierrors;
+		stats->oerrors += slave_stats.oerrors;
+		stats->imcasts += slave_stats.imcasts;
+		stats->rx_nombuf += slave_stats.rx_nombuf;
+		stats->fdirmatch += slave_stats.fdirmatch;
+		stats->fdirmiss += slave_stats.fdirmiss;
+		stats->tx_pause_xon += slave_stats.tx_pause_xon;
+		stats->rx_pause_xon += slave_stats.rx_pause_xon;
+		stats->tx_pause_xoff += slave_stats.tx_pause_xoff;
+		stats->rx_pause_xoff += slave_stats.rx_pause_xoff;
+	}
+}
+
+static void
+bond_ethdev_stats_reset(struct rte_eth_dev *dev)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < internals->slave_count; i++)
+		rte_eth_stats_reset(internals->slaves[i]);
+}
+
+static void
+bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals = eth_dev->data->dev_private;
+	int i;
+
+	internals->promiscuous_en = 1;
+
+	switch (internals->mode) {
+	/* Promiscuous mode is propagated to all slaves */
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BALANCE:
+	case BONDING_MODE_BROADCAST:
+		for (i = 0; i < internals->slave_count; i++)
+			rte_eth_promiscuous_enable(internals->slaves[i]);
+		break;
+	/* Promiscuous mode is propagated only to primary slave */
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		rte_eth_promiscuous_enable(internals->primary_port);
+
+	}
+}
+
+static void
+bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	int i;
+
+	internals->promiscuous_en = 0;
+
+	switch (internals->mode) {
+	/* Promiscuous mode is propagated to all slaves */
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BALANCE:
+	case BONDING_MODE_BROADCAST:
+		for (i = 0; i < internals->slave_count; i++)
+			rte_eth_promiscuous_disable(internals->slaves[i]);
+		break;
+	/* Promiscuous mode is propagated only to primary slave */
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		rte_eth_promiscuous_disable(internals->primary_port);
+	}
+}
+
+
+static void
+bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,
+		void *param)
+{
+	struct rte_eth_dev *bonded_eth_dev, *slave_eth_dev;
+	struct bond_dev_private *internals;
+	struct rte_eth_link link;
+
+	int i, bonded_port_id, valid_slave, active_pos = -1;
+
+	if (type != RTE_ETH_EVENT_INTR_LSC)
+		return;
+
+	if (param == NULL)
+		return;
+
+	bonded_port_id = *(uint8_t *)param;
+
+	bonded_eth_dev = &rte_eth_devices[bonded_port_id];
+	slave_eth_dev = &rte_eth_devices[port_id];
+
+	if (valid_bonded_ethdev(bonded_eth_dev))
+		return;
+
+	internals = bonded_eth_dev->data->dev_private;
+
+	/* If the device isn't started don't handle interrupts */
+	if (!bonded_eth_dev->data->dev_started)
+		return;
+
+	/* 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) {
+			valid_slave = 1;
+			break;
+		}
+	}
+
+	if (!valid_slave)
+		return;
+
+	/* Search for port in active port list */
+	for (i = 0; i < internals->active_slave_count; i++) {
+		if (port_id == internals->active_slaves[i]) {
+			active_pos = i;
+			break;
+		}
+	}
+
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status) {
+		if (active_pos == -1) {
+			/* if no active slave ports then set this port to be primary port */
+			if (internals->active_slave_count == 0) {
+				/* If first active slave, then change link status */
+				bonded_eth_dev->data->dev_link.link_status = 1;
+				internals->primary_port = port_id;
+
+				/* Inherit eth dev link properties from first active slave */
+				link_properties_set(bonded_eth_dev,
+						&(slave_eth_dev->data->dev_link));
+
+			}
+			internals->active_slaves[internals->active_slave_count++] = port_id;
+		}
+	} else {
+		if (active_pos != -1) {
+			/* Remove from active slave list */
+			for (i = active_pos; i < (internals->active_slave_count - 1); i++)
+				internals->active_slaves[i] = internals->active_slaves[i+1];
+
+			internals->active_slave_count--;
+
+			/* No active slaves, change link status to down and reset other
+			 * link properties */
+			if (internals->active_slave_count == 0)
+				link_properties_reset(bonded_eth_dev);
+
+			/* Update primary id, take first active slave from list or if none
+			 * available set to -1 */
+			if (port_id == internals->primary_port) {
+				if (internals->active_slave_count > 0)
+					internals->primary_port = internals->active_slaves[0];
+				else
+					internals->primary_port = internals->slaves[0];
+			}
+		}
+	}
+}
+
+static struct eth_dev_ops default_dev_ops = {
+		.dev_start = bond_ethdev_start,
+		.dev_stop = bond_ethdev_stop,
+		.dev_close = bond_ethdev_close,
+		.dev_configure = bond_ethdev_configure,
+		.dev_infos_get = bond_ethdev_info,
+		.rx_queue_setup = bond_ethdev_rx_queue_setup,
+		.tx_queue_setup = bond_ethdev_tx_queue_setup,
+		.rx_queue_release = bond_ethdev_rx_queue_release,
+		.tx_queue_release = bond_ethdev_tx_queue_release,
+		.link_update = bond_ethdev_link_update,
+		.stats_get = bond_ethdev_stats_get,
+		.stats_reset = bond_ethdev_stats_reset,
+		.promiscuous_enable = bond_ethdev_promiscuous_enable,
+		.promiscuous_disable = bond_ethdev_promiscuous_disable
+};
+
+static uint8_t
+number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; ((i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL)); i++) {
+		if (sockets < ms[i].socket_id)
+			sockets = ms[i].socket_id;
+	}
+
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+
+}
+
+int
+rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
+{
+	struct rte_pci_device *pci_dev = NULL;
+	struct bond_dev_private *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct eth_driver *eth_drv = NULL;
+	struct rte_pci_driver *pci_drv = NULL;
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+
+	if (name == NULL) {
+		RTE_LOG(ERR, PMD, "Invalid name specified\n");
+		goto err;
+	}
+
+	if (socket_id >= number_of_sockets()) {
+		RTE_LOG(ERR, PMD,
+				"%s: invalid socket id specified to create bonded device on.\n",
+				__func__);
+		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");
+		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");
+		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");
+		goto err;
+	}
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, socket_id);
+	if (internals == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to malloc internals on socket");
+		goto err;
+	}
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate();
+	if (eth_dev == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to allocate rte_eth_dev");
+		goto err;
+	}
+
+	pci_dev->numa_node = socket_id;
+	pci_drv->name = driver_name;
+
+	eth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);
+	eth_dev->driver = eth_drv;
+
+	eth_dev->data->dev_private = internals;
+	eth_dev->data->nb_rx_queues = (uint16_t)1;
+	eth_dev->data->nb_tx_queues = (uint16_t)1;
+
+	eth_dev->data->dev_link.link_status = 0;
+
+	eth_dev->data->mac_addrs = rte_zmalloc(name, ETHER_ADDR_LEN, 0);
+
+	eth_dev->data->dev_started = 0;
+	eth_dev->data->promiscuous = 0;
+	eth_dev->data->scattered_rx = 0;
+	eth_dev->data->all_multicast = 0;
+
+	eth_dev->dev_ops = &default_dev_ops;
+	eth_dev->pci_dev = pci_dev;
+
+	eth_dev->rx_pkt_burst = bond_ethdev_rx_burst;
+	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);
+		goto err;
+	}
+
+	internals->primary_port = 0;
+	internals->balance_xmit_policy = BALANCE_XMIT_POLICY_LAYER2;
+	internals->user_defined_mac = 0;
+	internals->link_props_set = 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:
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (pci_drv)
+		rte_free(pci_drv);
+	if (eth_drv)
+		rte_free(eth_drv);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+
+
+int
+rte_eth_bond_slave_add(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;
+	struct bond_dev_private *temp_internals;
+	struct rte_eth_link link_props;
+
+	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;
+
+	/*
+	 * 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;
+			}
+		}
+	}
+
+	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);
+
+	if (internals->slave_count < 1) {
+		/* 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));
+
+		/* Make primary slave */
+		internals->primary_port = slave_port_id;
+	} else {
+		/* Check slave link properties are supported if props are set,
+		 * all slaves must be the same */
+		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;
+			}
+		} else {
+			link_properties_set(bonded_eth_dev,
+					&(slave_eth_dev->data->dev_link));
+		}
+	}
+
+	internals->slave_count++;
+
+	/* Update all slave devices MACs*/
+	mac_address_slaves_update(bonded_eth_dev);
+
+	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",
+					slave_port_id);
+			goto err_add;
+		}
+	}
+
+	/* Register link status change callback with bonded device pointer as
+	 * argument*/
+	rte_eth_dev_callback_register(slave_port_id, RTE_ETH_EVENT_INTR_LSC,
+			bond_ethdev_lsc_event_callback, &bonded_eth_dev->data->port_id);
+
+	/* If bonded device is started then we can add the slave to our active
+	 * slave array */
+	if (bonded_eth_dev->data->dev_started) {
+		rte_eth_link_get_nowait(slave_port_id, &link_props);
+
+		 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)
+{
+	struct bond_dev_private *internals;
+	struct slave_conf *slave_conf;
+
+	int i;
+	int pos = -1;
+
+	/* Verify that port id's are valid bonded and slave ports */
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		goto err_del;
+
+	if (valid_slave_port_id(slave_port_id) != 0)
+		goto err_del;
+
+	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;
+
+		/* shift active slaves up active array list */
+		if (pos >= 0 && i < (internals->active_slave_count - 1))
+			internals->active_slaves[i] = internals->active_slaves[i+1];
+	}
+
+	if (pos >= 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;
+
+		/* shift slaves up list */
+		if (pos >= 0 && i < internals->slave_count)
+			internals->slaves[i] = internals->slaves[i+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,
+			bond_ethdev_lsc_event_callback,
+			&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));
+
+	slave_config_clear(internals, &rte_eth_devices[slave_port_id]);
+
+	internals->slave_count--;
+
+	/*  first slave in the active list will be the primary by default,
+	 *  otherwise use first device in list */
+	if (internals->primary_port == slave_port_id) {
+		if (internals->active_slave_count > 0)
+			internals->primary_port = internals->active_slaves[0];
+		else if (internals->slave_count > 0)
+			internals->primary_port = internals->slaves[0];
+		else
+			internals->primary_port = 0;
+	}
+
+	if (internals->active_slave_count < 1) {
+		/* reset device link properties as no slaves are active */
+		link_properties_reset(&rte_eth_devices[bonded_port_id]);
+
+		/* if no slaves are any longer attached to bonded device and MAC is not
+		 * user defined then clear MAC of bonded device as it will be reset
+		 * when a new slave is added */
+		if (internals->slave_count < 1 && !internals->user_defined_mac)
+			memset(rte_eth_devices[bonded_port_id].data->mac_addrs, 0,
+					sizeof(*(rte_eth_devices[bonded_port_id].data->mac_addrs)));
+	}
+
+	return 0;
+
+err_del:
+	RTE_LOG(ERR, PMD,
+			"Cannot remove slave device (not present in bonded device)\n");
+	return -1;
+
+}
+
+int
+rte_eth_bond_mode_set(uint8_t bonded_port_id, uint8_t mode)
+{
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	return bond_ethdev_mode_set(&rte_eth_devices[bonded_port_id], mode);
+}
+
+
+int
+rte_eth_bond_mode_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->mode;
+}
+
+int
+rte_eth_bond_primary_set(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+	struct bond_dev_private *internals;
+	int i;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (valid_slave_port_id(slave_port_id) != 0)
+		return -1;
+
+	internals =  rte_eth_devices[bonded_port_id].data->dev_private;
+
+	/* Search bonded device slave ports for new proposed primary port */
+	for (i = 0; i < internals->slave_count; i++) {
+		if (internals->slaves[i] == slave_port_id) {
+			/* Found slave device in active slave list */
+			internals->primary_port = slave_port_id;
+			return 0;
+		}
+	}
+
+	/* Slave is not bound to this master device */
+	return -1;
+}
+
+int
+rte_eth_bond_primary_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;
+
+	if (internals->slave_count < 1)
+		return -1;
+
+	return internals->primary_port;
+}
+
+int
+rte_eth_bond_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves)
+{
+	struct bond_dev_private *internals;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (slaves == NULL)
+		return -1;
+
+	internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+	*slaves = (uint8_t *)(&internals->slaves);
+
+	return internals->slave_count;
+
+}
+
+int
+rte_eth_bond_active_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves)
+{
+	struct bond_dev_private *internals;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (slaves == NULL)
+		return -1;
+
+	internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+	*slaves = (uint8_t *)(&internals->active_slaves);
+
+	return internals->active_slave_count;
+
+}
+
+
+int
+rte_eth_bond_mac_address_set(uint8_t bonded_port_id,
+		struct ether_addr *mac_addr)
+{
+	struct rte_eth_dev *bonded_eth_dev;
+	struct bond_dev_private *internals;
+
+	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;
+
+	/* Set MAC Address of Bonded Device */
+	if (mac_address_set(bonded_eth_dev, mac_addr))
+		return -1;
+
+	internals->user_defined_mac = 1;
+
+	/* Update all slave devices MACs*/
+	if (internals->slave_count > 0)
+		return mac_address_slaves_update(bonded_eth_dev);
+
+	return 0;
+}
+
+
+int
+rte_eth_bond_mac_address_reset(uint8_t bonded_port_id)
+{
+	struct rte_eth_dev *bonded_eth_dev;
+	struct bond_dev_private *internals;
+
+
+	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;
+
+	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)
+			return -1;
+
+		/* Update all slave devices MAC addresses */
+		return mac_address_slaves_update(bonded_eth_dev);
+	}
+	/* No need to update anything as no slaves present */
+	return 0;
+}
+
+int
+rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy)
+{
+	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;
+
+	switch (policy) {
+	case BALANCE_XMIT_POLICY_LAYER2:
+	case BALANCE_XMIT_POLICY_LAYER23:
+	case BALANCE_XMIT_POLICY_LAYER34:
+		internals->balance_xmit_policy = policy;
+		break;
+
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+
+int
+rte_eth_bond_xmit_policy_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->balance_xmit_policy;
+}
diff --git a/lib/librte_bond/rte_bond.h b/lib/librte_bond/rte_bond.h
new file mode 100644
index 0000000..97b6d5e
--- /dev/null
+++ b/lib/librte_bond/rte_bond.h
@@ -0,0 +1,228 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_BOND_H_
+#define _RTE_ETH_BOND_H_
+
+/**
+ * @file
+ * RTE Link Bonding Ethernet Device
+ * Link Bonding for 1GbE and 10GbE ports to allow the aggregation of multiple
+ * (slave) NICs into a single logical interface. The bonded device processes
+ * these interfaces based on the mode of operation specified and supported.
+ * This implementation supports 4 modes of operation round robin, active backup
+ * balance and broadcast. Providing redundant links, fault tolerance and/or
+ * load balancing of network ports
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ether.h>
+
+/** Link Bonding Mode Definitions */
+#define BONDING_MODE_ROUND_ROBIN		(0)
+#define BONDING_MODE_ACTIVE_BACKUP		(1)
+#define BONDING_MODE_BALANCE			(2)
+#define BONDING_MODE_BROADCAST			(3)
+
+/** Balance Mode Transmit Policy Types */
+#define BALANCE_XMIT_POLICY_LAYER2		(0)
+#define BALANCE_XMIT_POLICY_LAYER23		(1)
+#define BALANCE_XMIT_POLICY_LAYER34		(2)
+
+/**
+ * Create a bonded rte_eth_dev device
+ *
+ * @param name
+ * @param mode
+ * @param socket_id
+ *
+ * @return
+ *	Port Id of created rte_eth_dev on success, negative value otherwise
+ */
+int
+rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id);
+
+/**
+ * Add a rte_eth_dev device as a slave to the bonded device
+ *
+ * @param bonded_port_id
+ * @param slave_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Remove a slave rte_eth_dev device from the bonded device
+ *
+ * @param bonded_port_id
+ * @param slave_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Set link bonding mode of bonded device
+ *
+ * @param bonded_port_id
+ * @param mode
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mode_set(uint8_t bonded_port_id, uint8_t mode);
+
+/**
+ * Get link bonding mode of bonded device
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	link bonding mode on success, negative value otherwise
+ */
+int
+rte_eth_bond_mode_get(uint8_t bonded_port_id);
+
+/**
+ * Set slave rte_eth_dev as primary slave of bonded device
+ *
+ * @param bonded_port_id
+ * @param slave_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_primary_set(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Get primary slave of bonded device
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	Port Id of primary slave on success, -1 on failure
+ */
+int
+rte_eth_bond_primary_get(uint8_t bonded_port_id);
+
+/**
+ * Populate an array with list of the slaves port id's of the bonded device
+ *
+ * @param bonded_port_id
+ * @param slaves
+ *
+ * @return
+ *	number of slaves associated with bonded device on success,
+ *	negative value otherwise
+ */
+int
+rte_eth_bond_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves);
+
+/**
+ * Populate an array with list of the active slaves port id's of the bonded
+ * device.
+ *
+ * @param bonded_port_id
+ * @param slaves
+ *
+ * @return
+ *	number of active slaves associated with bonded device on success,
+ *	negative value otherwise
+ */
+int
+rte_eth_bond_active_slaves_get(uint8_t bonded_port_id, const uint8_t **slaves);
+
+/**
+ * Set explicit MAC address to use on bonded device and it's slaves.
+ *
+ * @param bonded_port_id
+ * @param mac_addr
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mac_address_set(uint8_t bonded_port_id,
+		struct ether_addr *mac_addr);
+
+/**
+ * Reset bonded device to use MAC from primary slave on bonded device and it's
+ * slaves.
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mac_address_reset(uint8_t bonded_port_id);
+
+/**
+ * Set the transmit policy for bonded device to use when it is operating in
+ * balance mode
+ *
+ * @param bonded_port_id
+ * @param policy
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy);
+
+/**
+ * Get the transmit policy set on bonded device for balance mode operation
+ *
+ * @param bonded_port_id
+ *
+ * @return
+ *	balance transmit policy on success, negative value otherwise
+ */
+int
+rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index a836577..a803a5c 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -177,8 +177,13 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_PCAP),y)
 LDLIBS += -lrte_pmd_pcap -lpcap
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_BOND),y)
+LDLIBS += -lrte_bond
 endif
 
+endif
+
+
 LDLIBS += $(EXECENV_LDLIBS)
 
 LDLIBS += --end-group
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v2 2/4] Link bonding unit tests, including: - code to generate packet bursts for testing rx and tx functionality of bonded device - virtual/stubbed out ethdev for use as slave ethdev in testing - checkpack fixes
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 2/4] Link bonding unit tests, including: - code to generate packet bursts for testing rx and tx functionality of bonded device - virtual/stubbed out ethdev for use as slave ethdev in testing - checkpack fixes declan.doherty
@ 2014-06-04 15:18     ` declan.doherty
  0 siblings, 0 replies; 127+ messages in thread
From: declan.doherty @ 2014-06-04 15:18 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 app/test/Makefile                 |    3 +
 app/test/commands.c               |    3 +
 app/test/packet_burst_generator.c |  289 +++
 app/test/packet_burst_generator.h |   78 +
 app/test/test.h                   |    1 +
 app/test/test_link_bonding.c      | 3943 +++++++++++++++++++++++++++++++++++++
 app/test/virtual_pmd.c            |  574 ++++++
 app/test/virtual_pmd.h            |   74 +
 8 files changed, 4965 insertions(+)
 create mode 100644 app/test/packet_burst_generator.c
 create mode 100644 app/test/packet_burst_generator.h
 create mode 100644 app/test/test_link_bonding.c
 create mode 100644 app/test/virtual_pmd.c
 create mode 100644 app/test/virtual_pmd.h

diff --git a/app/test/Makefile b/app/test/Makefile
index b49785e..ac55a11 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_ring_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_rwlock.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_timer.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_mempool.c
+SRCS-$(CONFIG_RTE_APP_TEST) += test_link_bonding.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_mempool_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_mbuf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_logs.c
@@ -94,6 +95,8 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_common.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_timer_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_ivshmem.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_devargs.c
+SRCS-$(CONFIG_RTE_APP_TEST) += virtual_pmd.c
+SRCS-$(CONFIG_RTE_APP_TEST) += packet_burst_generator.c
 
 ifeq ($(CONFIG_RTE_APP_TEST),y)
 SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
diff --git a/app/test/commands.c b/app/test/commands.c
index efa8566..4d0ec3b 100644
--- a/app/test/commands.c
+++ b/app/test/commands.c
@@ -157,6 +157,8 @@ static void cmd_autotest_parsed(void *parsed_result,
 		ret = test_timer();
 	if (!strcmp(res->autotest, "timer_perf_autotest"))
 		ret = test_timer_perf();
+	if (!strcmp(res->autotest, "link_bonding_autotest"))
+		ret = test_link_bonding();
 	if (!strcmp(res->autotest, "mempool_autotest"))
 		ret = test_mempool();
 	if (!strcmp(res->autotest, "mempool_perf_autotest"))
@@ -221,6 +223,7 @@ cmdline_parse_token_string_t cmd_autotest_autotest =
 			"alarm_autotest#interrupt_autotest#"
 			"version_autotest#eal_fs_autotest#"
 			"cmdline_autotest#func_reentrancy_autotest#"
+			"link_bonding_autotest#"
 			"mempool_perf_autotest#hash_perf_autotest#"
 			"memcpy_perf_autotest#ring_perf_autotest#"
 			"red_autotest#meter_autotest#sched_autotest#"
diff --git a/app/test/packet_burst_generator.c b/app/test/packet_burst_generator.c
new file mode 100644
index 0000000..8c535f6
--- /dev/null
+++ b/app/test/packet_burst_generator.c
@@ -0,0 +1,289 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_byteorder.h>
+#include <rte_mbuf.h>
+
+#include "packet_burst_generator.h"
+
+#define UDP_SRC_PORT 1024
+#define UDP_DST_PORT 1024
+
+
+#define IP_DEFTTL  64   /* from RFC 1340. */
+#define IP_VERSION 0x40
+#define IP_HDRLEN  0x05 /* default IP header length == five 32-bits words. */
+#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
+
+static void
+copy_buf_to_pkt_segs(void *buf, unsigned len, struct rte_mbuf *pkt,
+		unsigned offset)
+{
+	struct rte_mbuf *seg;
+	void *seg_buf;
+	unsigned copy_len;
+
+	seg = pkt;
+	while (offset >= seg->pkt.data_len) {
+		offset -= seg->pkt.data_len;
+		seg = seg->pkt.next;
+	}
+	copy_len = seg->pkt.data_len - offset;
+	seg_buf = ((char *) seg->pkt.data + offset);
+	while (len > copy_len) {
+		rte_memcpy(seg_buf, buf, (size_t) copy_len);
+		len -= copy_len;
+		buf = ((char *) buf + copy_len);
+		seg = seg->pkt.next;
+		seg_buf = seg->pkt.data;
+	}
+	rte_memcpy(seg_buf, buf, (size_t) len);
+}
+
+static inline void
+copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
+{
+	if (offset + len <= pkt->pkt.data_len) {
+		rte_memcpy(((char *) pkt->pkt.data + offset), buf, (size_t) len);
+		return;
+	}
+	copy_buf_to_pkt_segs(buf, len, pkt, offset);
+}
+
+
+void
+initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint8_t vlan_enabled, uint16_t van_id)
+{
+	ether_addr_copy(dst_mac, &eth_hdr->d_addr);
+	ether_addr_copy(src_mac, &eth_hdr->s_addr);
+
+	if (vlan_enabled) {
+		struct vlan_hdr *vhdr = (struct vlan_hdr *)((uint8_t *)eth_hdr +
+				sizeof(struct ether_hdr));
+
+		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+
+		vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		vhdr->vlan_tci = van_id;
+	} else {
+		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	}
+
+}
+
+uint16_t
+initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
+		uint16_t dst_port, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct udp_hdr));
+
+	udp_hdr->src_port = rte_cpu_to_be_16(src_port);
+	udp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
+	udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len);
+	udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
+
+	return pkt_len;
+}
+
+
+uint16_t
+initialize_ipv6_header(struct ipv6_hdr *ip_hdr, uint8_t *src_addr,
+		uint8_t *dst_addr, uint16_t pkt_data_len)
+{
+	ip_hdr->vtc_flow = 0;
+	ip_hdr->payload_len = pkt_data_len;
+	ip_hdr->proto = IPPROTO_UDP;
+	ip_hdr->hop_limits = IP_DEFTTL;
+
+	rte_memcpy(ip_hdr->src_addr, src_addr, sizeof(ip_hdr->src_addr));
+	rte_memcpy(ip_hdr->dst_addr, dst_addr, sizeof(ip_hdr->dst_addr));
+
+	return (uint16_t) (pkt_data_len + sizeof(struct ipv6_hdr));
+}
+
+uint16_t
+initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+		uint32_t dst_addr, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+	uint16_t *ptr16;
+	uint32_t ip_cksum;
+
+	/*
+	 * Initialize IP header.
+	 */
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct ipv4_hdr));
+
+	ip_hdr->version_ihl   = IP_VHL_DEF;
+	ip_hdr->type_of_service   = 0;
+	ip_hdr->fragment_offset = 0;
+	ip_hdr->time_to_live   = IP_DEFTTL;
+	ip_hdr->next_proto_id = IPPROTO_UDP;
+	ip_hdr->packet_id = 0;
+	ip_hdr->total_length   = rte_cpu_to_be_16(pkt_len);
+	ip_hdr->src_addr = rte_cpu_to_be_32(src_addr);
+	ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr);
+
+	/*
+	 * Compute IP header checksum.
+	 */
+	ptr16 = (uint16_t *)ip_hdr;
+	ip_cksum = 0;
+	ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
+	ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
+	ip_cksum += ptr16[4];
+	ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
+	ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
+
+	/*
+	 * Reduce 32 bit checksum to 16 bits and complement it.
+	 */
+	ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
+		(ip_cksum & 0x0000FFFF);
+	if (ip_cksum > 65535)
+		ip_cksum -= 65535;
+	ip_cksum = (~ip_cksum) & 0x0000FFFF;
+	if (ip_cksum == 0)
+		ip_cksum = 0xFFFF;
+	ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
+
+	return pkt_len;
+}
+
+
+
+/*
+ * The maximum number of segments per packet is used when creating
+ * scattered transmit packets composed of a list of mbufs.
+ */
+#define RTE_MAX_SEGS_PER_PKT 255 /**< pkt.nb_segs is a 8-bit unsigned char. */
+
+#define TXONLY_DEF_PACKET_LEN 64
+#define TXONLY_DEF_PACKET_LEN_128 128
+
+uint16_t tx_pkt_length = TXONLY_DEF_PACKET_LEN;
+uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT] = {
+		TXONLY_DEF_PACKET_LEN_128,
+};
+
+uint8_t  tx_pkt_nb_segs = 1;
+
+int
+generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
+		struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr,
+		uint8_t ipv4, struct udp_hdr *udp_hdr, int nb_pkt_per_burst)
+{
+	int i, nb_pkt = 0;
+	size_t eth_hdr_size;
+
+	struct rte_mbuf *pkt_seg;
+	struct rte_mbuf *pkt;
+
+	for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+		pkt = rte_pktmbuf_alloc(mp);
+		if (pkt == NULL) {
+nomore_mbuf:
+			if (nb_pkt == 0)
+				return -1;
+			break;
+		}
+
+		pkt->pkt.data_len = tx_pkt_seg_lengths[0];
+		pkt_seg = pkt;
+		for (i = 1; i < tx_pkt_nb_segs; i++) {
+			pkt_seg->pkt.next = rte_pktmbuf_alloc(mp);
+			if (pkt_seg->pkt.next == NULL) {
+				pkt->pkt.nb_segs = i;
+				rte_pktmbuf_free(pkt);
+				goto nomore_mbuf;
+			}
+			pkt_seg = pkt_seg->pkt.next;
+			pkt_seg->pkt.data_len = tx_pkt_seg_lengths[i];
+		}
+		pkt_seg->pkt.next = NULL; /* Last segment of packet. */
+
+		/*
+		 * Copy headers in first packet segment(s).
+		 */
+		if (vlan_enabled)
+			eth_hdr_size = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_hdr_size = sizeof(struct ether_hdr);
+
+		copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0);
+
+		if (ipv4) {
+			copy_buf_to_pkt(ip_hdr, sizeof(struct ipv4_hdr), pkt, eth_hdr_size);
+			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size +
+					sizeof(struct ipv4_hdr));
+		} else {
+			copy_buf_to_pkt(ip_hdr, sizeof(struct ipv6_hdr), pkt, eth_hdr_size);
+			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size +
+					sizeof(struct ipv6_hdr));
+		}
+
+		/*
+		 * Complete first mbuf of packet and append it to the
+		 * burst of packets to be transmitted.
+		 */
+		pkt->pkt.nb_segs = tx_pkt_nb_segs;
+		pkt->pkt.pkt_len = tx_pkt_length;
+		pkt->pkt.vlan_macip.f.l2_len = eth_hdr_size;
+
+		if (ipv4) {
+			pkt->pkt.vlan_macip.f.vlan_tci  = ETHER_TYPE_IPv4;
+			pkt->pkt.vlan_macip.f.l3_len = sizeof(struct ipv4_hdr);
+
+			if (vlan_enabled)
+				pkt->ol_flags = PKT_RX_IPV4_HDR | PKT_RX_VLAN_PKT;
+			else
+				pkt->ol_flags = PKT_RX_IPV4_HDR;
+		} else {
+			pkt->pkt.vlan_macip.f.vlan_tci  = ETHER_TYPE_IPv6;
+			pkt->pkt.vlan_macip.f.l3_len = sizeof(struct ipv6_hdr);
+
+			if (vlan_enabled)
+				pkt->ol_flags = PKT_RX_IPV6_HDR | PKT_RX_VLAN_PKT;
+			else
+				pkt->ol_flags = PKT_RX_IPV6_HDR;
+		}
+
+		pkts_burst[nb_pkt] = pkt;
+	}
+
+	return nb_pkt;
+}
+
diff --git a/app/test/packet_burst_generator.h b/app/test/packet_burst_generator.h
new file mode 100644
index 0000000..5b3cd6c
--- /dev/null
+++ b/app/test/packet_burst_generator.h
@@ -0,0 +1,78 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PACKET_BURST_GENERATOR_H_
+#define PACKET_BURST_GENERATOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+
+
+#define IPV4_ADDR(a, b, c, d)(((a & 0xff) << 24) | ((b & 0xff) << 16) | \
+		((c & 0xff) << 8) | (d & 0xff))
+
+
+void
+initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint8_t vlan_enabled, uint16_t van_id);
+
+uint16_t
+initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
+		uint16_t dst_port, uint16_t pkt_data_len);
+
+
+uint16_t
+initialize_ipv6_header(struct ipv6_hdr *ip_hdr, uint8_t *src_addr,
+		uint8_t *dst_addr, uint16_t pkt_data_len);
+
+uint16_t
+initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+		uint32_t dst_addr, uint16_t pkt_data_len);
+
+int
+generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
+		struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr,
+		uint8_t ipv4, struct udp_hdr *udp_hdr, int nb_pkt_per_burst);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* PACKET_BURST_GENERATOR_H_ */
diff --git a/app/test/test.h b/app/test/test.h
index 1945d29..7213e1a 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -94,6 +94,7 @@ int test_pmd_ring(void);
 int test_ivshmem(void);
 int test_kvargs(void);
 int test_devargs(void);
+int test_link_bonding(void);
 
 int test_pci_run;
 
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
new file mode 100644
index 0000000..461d132
--- /dev/null
+++ b/app/test/test_link_bonding.c
@@ -0,0 +1,3943 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_memory.h>
+#include <rte_bond.h>
+
+#include "virtual_pmd.h"
+#include "packet_burst_generator.h"
+
+#include "test.h"
+
+#define TEST_MAX_NUMBER_OF_PORTS (16)
+
+#define RX_RING_SIZE 128
+#define RX_FREE_THRESH 32
+#define RX_PTHRESH 8
+#define RX_HTHRESH 8
+#define RX_WTHRESH 0
+
+#define TX_RING_SIZE 512
+#define TX_FREE_THRESH 32
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+#define TX_RSBIT_THRESH 32
+#define TX_Q_FLAGS (ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOVLANOFFL |\
+	ETH_TXQ_FLAGS_NOXSUMSCTP | ETH_TXQ_FLAGS_NOXSUMUDP | \
+	ETH_TXQ_FLAGS_NOXSUMTCP)
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define MBUF_CACHE_SIZE (250)
+#define BURST_SIZE (32)
+
+#define DEFAULT_MBUF_DATA_SIZE	(2048)
+#define RTE_TEST_RX_DESC_MAX	(2048)
+#define RTE_TEST_TX_DESC_MAX	(2048)
+#define MAX_PKT_BURST			(512)
+#define DEF_PKT_BURST			(16)
+
+#define BONDED_DEV_NAME			("unit_test_bonded_device")
+
+#define INVALID_SOCKET_ID		(-1)
+#define INVALID_PORT_ID			(-1)
+#define INVALID_BONDING_MODE	(-1)
+
+
+uint8_t slave_mac[] = {0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 };
+uint8_t bonded_mac[] = {0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
+
+struct link_bonding_unittest_params {
+	int8_t bonded_port_id;
+	int8_t slave_port_ids[TEST_MAX_NUMBER_OF_PORTS];
+	uint8_t bonded_slave_count;
+	uint8_t bonding_mode;
+
+	uint16_t nb_rx_q;
+	uint16_t nb_tx_q;
+
+	struct rte_mempool *mbuf_pool;
+
+	struct ether_addr *default_slave_mac;
+	struct ether_addr *default_bonded_mac;
+
+	/* Packet Headers */
+	struct ether_hdr *pkt_eth_hdr;
+	struct ipv4_hdr *pkt_ipv4_hdr;
+	struct ipv6_hdr *pkt_ipv6_hdr;
+	struct udp_hdr *pkt_udp_hdr;
+
+};
+
+static struct ipv4_hdr pkt_ipv4_hdr;
+static struct ipv6_hdr pkt_ipv6_hdr;
+static struct udp_hdr pkt_udp_hdr;
+
+static struct link_bonding_unittest_params default_params  = {
+	.bonded_port_id = -1,
+	.slave_port_ids = { 0 },
+	.bonded_slave_count = 0,
+	.bonding_mode = BONDING_MODE_ROUND_ROBIN,
+
+	.nb_rx_q = 1,
+	.nb_tx_q = 1,
+
+	.mbuf_pool = NULL,
+
+	.default_slave_mac = (struct ether_addr *)slave_mac,
+	.default_bonded_mac = (struct ether_addr *)bonded_mac,
+
+	.pkt_eth_hdr = NULL,
+	.pkt_ipv4_hdr = &pkt_ipv4_hdr,
+	.pkt_ipv6_hdr = &pkt_ipv6_hdr,
+	.pkt_udp_hdr = &pkt_udp_hdr
+
+};
+
+static struct link_bonding_unittest_params *test_params = &default_params;
+
+static uint8_t src_mac[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
+static uint8_t dst_mac_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
+static uint8_t dst_mac_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAB };
+
+static uint32_t src_addr = IPV4_ADDR(192, 168, 1, 98);
+static uint32_t dst_addr_0 = IPV4_ADDR(192, 168, 1, 98);
+static uint32_t dst_addr_1 = IPV4_ADDR(193, 166, 10, 97);
+
+static uint8_t src_ipv6_addr[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA  };
+static uint8_t dst_ipv6_addr_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA,  0xFF, 0xAA , 0xFF, 0xAA, 0xFF, 0xAA  };
+static uint8_t dst_ipv6_addr_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA , 0xFF, 0xAB  };
+
+static uint16_t src_port = 1024;
+static uint16_t dst_port_0 = 1024;
+static uint16_t dst_port_1 = 2024;
+
+static uint16_t vlan_id = 0x100;
+
+struct rte_eth_rxmode rx_mode = {
+	.max_rx_pkt_len = ETHER_MAX_LEN, /**< Default maximum frame length. */
+	.split_hdr_size = 0,
+	.header_split   = 0, /**< Header Split disabled. */
+	.hw_ip_checksum = 0, /**< IP checksum offload disabled. */
+	.hw_vlan_filter = 1, /**< VLAN filtering enabled. */
+	.hw_vlan_strip  = 1, /**< VLAN strip enabled. */
+	.hw_vlan_extend = 0, /**< Extended VLAN disabled. */
+	.jumbo_frame    = 0, /**< Jumbo Frame Support disabled. */
+	.hw_strip_crc   = 0, /**< CRC stripping by hardware disabled. */
+};
+
+struct rte_fdir_conf fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.flexbytes_offset = 0x6,
+	.drop_queue = 127,
+};
+
+static struct rte_eth_conf default_pmd_conf = {
+	.rxmode = {
+		.mq_mode = ETH_MQ_RX_NONE,
+		.max_rx_pkt_len = ETHER_MAX_LEN,
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload enabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.lpbk_mode = 0,
+};
+
+static const struct rte_eth_rxconf rx_conf_default = {
+	.rx_thresh = {
+		.pthresh = RX_PTHRESH,
+		.hthresh = RX_HTHRESH,
+		.wthresh = RX_WTHRESH,
+	},
+	.rx_free_thresh = RX_FREE_THRESH,
+	.rx_drop_en = 0,
+};
+
+static struct rte_eth_txconf tx_conf_default = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = TX_FREE_THRESH,
+	.tx_rs_thresh = TX_RSBIT_THRESH,
+	.txq_flags = TX_Q_FLAGS
+
+};
+
+static int
+configure_ethdev(uint8_t port_id, uint8_t start)
+{
+	int q_id;
+
+	if (rte_eth_dev_configure(port_id, test_params->nb_rx_q,
+			test_params->nb_tx_q, &default_pmd_conf) != 0) {
+		goto error;
+	}
+
+	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,
+				rte_eth_dev_socket_id(port_id), &rx_conf_default,
+				test_params->mbuf_pool) < 0) {
+			goto error;
+		}
+	}
+
+	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;
+		}
+	}
+
+	if (start) {
+		if (rte_eth_dev_start(port_id) < 0) {
+			printf("Failed to start device (%d).\n", port_id);
+			goto error;
+		}
+	}
+	return 0;
+
+error:
+	printf("Failed to configure ethdev %d", port_id);
+	return -1;
+}
+
+
+static int
+test_setup(void)
+{
+	int i, retval, nb_mbuf_per_pool;
+	struct ether_addr *mac_addr = (struct ether_addr *)slave_mac;
+
+	/* Allocate ethernet packet header with space for VLAN header */
+	test_params->pkt_eth_hdr = malloc(sizeof(struct ether_hdr) +
+			sizeof(struct vlan_hdr));
+	if (test_params->pkt_eth_hdr == NULL) {
+		printf("ethernet header struct allocation failed!\n");
+		return -1;
+	}
+
+
+	nb_mbuf_per_pool = RTE_TEST_RX_DESC_MAX + DEF_PKT_BURST +
+			RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;
+
+	test_params->mbuf_pool = rte_mempool_create("MBUF_POOL", nb_mbuf_per_pool,
+			MBUF_SIZE, MBUF_CACHE_SIZE, sizeof(struct rte_pktmbuf_pool_private),
+			rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
+			rte_socket_id(), 0);
+	if (test_params->mbuf_pool == NULL) {
+		printf("rte_mempool_create failed\n");
+		return -1;
+	}
+
+	/* Create / Initialize virtual eth devs */
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i;
+
+		test_params->slave_port_ids[i] = virtual_ethdev_create("slave_pmd_1",
+				mac_addr, rte_socket_id());
+		if (test_params->slave_port_ids[i] < 0) {
+			printf("Failed to create virtual pmd eth device.\n");
+			return -1;
+		}
+
+		retval = configure_ethdev(test_params->slave_port_ids[i], 1);
+		if (retval != 0) {
+			printf("Failed to configure virtual pmd eth device.\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+test_create_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	const uint8_t *slaves;
+
+	test_params->bonded_port_id = rte_eth_bond_create(BONDED_DEV_NAME,
+			test_params->bonding_mode, rte_socket_id());
+	if (test_params->bonded_port_id < 0) {
+		printf("\t Failed to create bonded device.\n");
+		return -1;
+	}
+
+	retval = configure_ethdev(test_params->bonded_port_id, 0);
+	if (retval != 0) {
+		printf("Failed to configure bonded pmd eth device.\n");
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count > 0) {
+		printf("Number of slaves is great than expected.\n");
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count > 0) {
+		printf("Number of active slaves is great than expected.\n");
+		return -1;
+	}
+
+
+	if (rte_eth_bond_mode_get(test_params->bonded_port_id) !=
+			test_params->bonding_mode) {
+		printf("Bonded device mode not as expected.\n");
+		return -1;
+
+	}
+
+	return 0;
+}
+
+
+static int
+test_create_bonded_device_with_invalid_params(void)
+{
+	int port_id;
+
+	test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN;
+
+	/* Invalid name */
+	port_id = rte_eth_bond_create(NULL, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	test_params->bonding_mode = INVALID_BONDING_MODE;
+
+	/* Invalid bonding mode */
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN;
+
+	/* Invalid socket id */
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			INVALID_SOCKET_ID);
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_add_slave_to_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	const uint8_t *slaves;
+
+	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;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	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;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count != 0) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				current_slave_count, 0);
+		return -1;
+	}
+
+	test_params->bonded_slave_count++;
+
+	return 0;
+}
+
+static int
+test_add_slave_to_invalid_bonded_device(void)
+{
+	int retval;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_slave_add(test_params->bonded_port_id + 5,
+			test_params->slave_port_ids[test_params->bonded_slave_count]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_slave_add(test_params->slave_port_ids[0],
+			test_params->slave_port_ids[test_params->bonded_slave_count]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+test_remove_slave_from_bonded_device(void)
+{
+	int retval, current_slave_count;
+	struct ether_addr read_mac_addr, *mac_addr;
+	const uint8_t *slaves;
+
+	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;
+	}
+
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	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;
+	}
+
+
+	mac_addr = (struct ether_addr *)slave_mac;
+	mac_addr->addr_bytes[ETHER_ADDR_LEN-1] =
+			test_params->slave_port_ids[test_params->bonded_slave_count-1];
+
+	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;
+	}
+
+	rte_eth_stats_reset(
+			test_params->slave_port_ids[test_params->bonded_slave_count-1]);
+
+	virtual_ethdev_simulate_link_status_interrupt(test_params->bonded_port_id,
+			0);
+
+	test_params->bonded_slave_count--;
+
+	return 0;
+}
+
+static int
+test_remove_slave_from_invalid_bonded_device(void)
+{
+	int retval;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_slave_remove(test_params->bonded_port_id + 5,
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_slave_remove(test_params->slave_port_ids[0],
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_add_already_bonded_slave_to_bonded_device(void)
+{
+	int retval, port_id, current_slave_count;
+	const uint8_t *slaves;
+
+	test_add_slave_to_bonded_device();
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count != 1) {
+		printf("Number of slaves (%d) is not that expected (%d).\n",
+				current_slave_count, 1);
+		return -1;
+	}
+
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id < 0) {
+		printf("Failed to create bonded device.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_slave_add(port_id,
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Added slave (%d) to bonded port (%d) unexpectedly.\n",
+				test_params->slave_port_ids[test_params->bonded_slave_count-1],
+				port_id);
+		return -1;
+	}
+
+	return test_remove_slave_from_bonded_device();
+}
+
+
+static int
+test_get_slaves_from_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	const uint8_t *slaves;
+
+	retval = test_add_slave_to_bonded_device();
+	if (retval != 0)
+		return -1;
+
+	/* Invalid port id */
+	current_slave_count = rte_eth_bond_slaves_get(INVALID_PORT_ID, &slaves);
+	if (current_slave_count >= 0)
+		return -1;
+
+	current_slave_count = rte_eth_bond_active_slaves_get(INVALID_PORT_ID,
+			&slaves);
+	if (current_slave_count >= 0)
+		return -1;
+
+	/* Invalid slaves pointer */
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			NULL);
+	if (current_slave_count >= 0)
+		return -1;
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, NULL);
+	if (current_slave_count >= 0)
+		return -1;
+
+	/* non bonded device*/
+	current_slave_count = rte_eth_bond_slaves_get(
+			test_params->slave_port_ids[0], NULL);
+	if (current_slave_count >= 0)
+		return -1;
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->slave_port_ids[0],	NULL);
+	if (current_slave_count >= 0)
+		return -1;
+
+	retval = test_remove_slave_from_bonded_device();
+	if (retval != 0)
+		return -1;
+
+	return 0;
+}
+
+
+static int
+test_add_remove_multiple_slaves_to_from_bonded_device(void)
+{
+	int i;
+
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		if (test_add_slave_to_bonded_device() != 0)
+			return -1;
+	}
+
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		if (test_remove_slave_from_bonded_device() != 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+static void
+enable_bonded_slaves(void)
+{
+	int i;
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 1);
+	}
+}
+
+static int
+test_start_bonded_device(void)
+{
+	struct rte_eth_link link_status;
+
+	int retval, current_slave_count, current_bonding_mode, primary_port;
+	const uint8_t *slaves;
+
+	/* Add slave to bonded device*/
+	if (test_add_slave_to_bonded_device() != 0)
+		return -1;
+
+	retval = rte_eth_dev_start(test_params->bonded_port_id);
+	if (retval != 0) {
+		printf("Failed to start bonded pmd eth device.\n");
+		return -1;
+	}
+
+	/* Change link status of virtual pmd so it will be added to the active
+	 * slave list of the bonded device*/
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[test_params->bonded_slave_count-1], 1);
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of active slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id);
+	if (current_bonding_mode != test_params->bonding_mode) {
+		printf("Bonded device mode (%d) is not expected value (%d).\n",
+				current_bonding_mode, test_params->bonding_mode);
+		return -1;
+
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[0]) {
+		printf("Primary port (%d) is not expected value (%d).\n",
+				primary_port, test_params->slave_port_ids[0]);
+		return -1;
+
+	}
+
+	rte_eth_link_get(test_params->bonded_port_id, &link_status);
+	if (!link_status.link_status) {
+		printf("Bonded port (%d) status (%d) is not expected value (%d).\n",
+				test_params->bonded_port_id, link_status.link_status, 1);
+		return -1;
+
+	}
+
+	return 0;
+}
+
+static int
+test_stop_bonded_device(void)
+{
+	int current_slave_count;
+	const uint8_t *slaves;
+
+	struct rte_eth_link link_status;
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	rte_eth_link_get(test_params->bonded_port_id, &link_status);
+	if (link_status.link_status) {
+		printf("Bonded port (%d) status (%d) is not expected value (%d).\n",
+				test_params->bonded_port_id, link_status.link_status, 0);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (current_slave_count != 0) {
+		printf("Number of active slaves (%d) is not expected value (%d).\n",
+				current_slave_count, 0);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int remove_slaves_and_stop_bonded_device(void)
+{
+	/* Clean up and remove slaves from bonded device */
+	while (test_params->bonded_slave_count > 0) {
+		if (test_remove_slave_from_bonded_device() != 0) {
+			printf("test_remove_slave_from_bonded_device failed\n");
+			return -1;
+		}
+	}
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+	rte_eth_stats_reset(test_params->bonded_port_id);
+	rte_eth_bond_mac_address_reset(test_params->bonded_port_id);
+
+	return 0;
+}
+
+static int
+test_set_bonding_mode(void)
+{
+	int i;
+	int retval, bonding_mode;
+
+	int bonding_modes[] = { BONDING_MODE_ROUND_ROBIN,
+							BONDING_MODE_ACTIVE_BACKUP,
+							BONDING_MODE_BALANCE,
+							BONDING_MODE_BROADCAST };
+
+	/* Test supported link bonding modes */
+	for (i = 0; i < (int)RTE_DIM(bonding_modes);	i++) {
+		/* Invalid port ID */
+		retval = rte_eth_bond_mode_set(INVALID_PORT_ID, bonding_modes[i]);
+		if (retval == 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					INVALID_PORT_ID);
+			return -1;
+		}
+
+		/* Non bonded device */
+		retval = rte_eth_bond_mode_set(test_params->slave_port_ids[0],
+				bonding_modes[i]);
+		if (retval == 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					test_params->slave_port_ids[0]);
+			return -1;
+		}
+
+		retval = rte_eth_bond_mode_set(test_params->bonded_port_id,
+				bonding_modes[i]);
+		if (retval != 0) {
+			printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+					test_params->bonded_port_id, bonding_modes[i]);
+			return -1;
+		}
+
+		bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id);
+		if (bonding_mode != bonding_modes[i]) {
+			printf("Link bonding mode (%d) of port (%d) is not expected value (%d).\n",
+					bonding_mode, test_params->bonded_port_id,
+					bonding_modes[i]);
+			return -1;
+		}
+
+
+		/* Invalid port ID */
+		bonding_mode = rte_eth_bond_mode_get(INVALID_PORT_ID);
+		if (bonding_mode >= 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					INVALID_PORT_ID);
+			return -1;
+		}
+
+
+		/* Non bonded device */
+		bonding_mode = rte_eth_bond_mode_get(test_params->slave_port_ids[0]);
+		if (bonding_mode >= 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					test_params->slave_port_ids[0]);
+			return -1;
+		}
+
+	}
+
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_set_primary_slave(void)
+{
+	int i, j, retval;
+	struct ether_addr read_mac_addr;
+	struct ether_addr *expected_mac_addr;
+
+	/* Add 4 slaves to bonded device */
+	for (i = test_params->bonded_slave_count; i < 4; i++) {
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave to bonded device.\n");
+			return -1;
+		}
+	}
+	retval = rte_eth_bond_mode_set(test_params->bonded_port_id,
+			BONDING_MODE_ROUND_ROBIN);
+	if (retval != 0) {
+		printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+				test_params->bonded_port_id, BONDING_MODE_ROUND_ROBIN);
+		return -1;
+	}
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_primary_set(INVALID_PORT_ID,
+			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) {
+			printf("Failed to set bonded port (%d) primary port to (%d)\n",
+					test_params->bonded_port_id,
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+
+		retval = rte_eth_bond_primary_get(test_params->bonded_port_id);
+		if (retval < 0) {
+			printf("Failed to read primary port from bonded port (%d)\n",
+					test_params->bonded_port_id);
+			return -1;
+		} else if (retval != test_params->slave_port_ids[i]) {
+			printf("Bonded port (%d) primary port (%d) not expected value (%d)\n",
+					test_params->bonded_port_id, retval,
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+
+		/* 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;
+
+		expected_mac_addr = (struct ether_addr *)&slave_mac;
+		expected_mac_addr->addr_bytes[ETHER_ADDR_LEN-1] =
+				test_params->slave_port_ids[i];
+
+		/* Check primary slave MAC */
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(expected_mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("bonded port mac address not set to that of primary port\n");
+			return -1;
+		}
+
+		/* Check bonded MAC */
+		rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+		if (memcmp(&read_mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("bonded port mac address not set to that of primary port\n");
+			return -1;
+		}
+
+		/* Check other slaves MACs */
+		for (j = 0; j < 4; j++) {
+			if (j != i) {
+				rte_eth_macaddr_get(test_params->slave_port_ids[j],
+						&read_mac_addr);
+				if (memcmp(expected_mac_addr, &read_mac_addr,
+						sizeof(read_mac_addr))) {
+					printf("slave port mac address not set to that of primary port\n");
+					return -1;
+				}
+			}
+		}
+	}
+
+
+	/* Test with none existent port */
+	retval = rte_eth_bond_primary_get(test_params->bonded_port_id + 10);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	/* Test with slave port */
+	retval = rte_eth_bond_primary_get(test_params->slave_port_ids[0]);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	if (remove_slaves_and_stop_bonded_device() != 0)
+		return -1;
+
+	/* No slaves  */
+	retval = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_set_explicit_bonded_mac(void)
+{
+	int i, retval;
+	struct ether_addr read_mac_addr;
+	struct ether_addr *mac_addr;
+
+	uint8_t explicit_bonded_mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01 };
+
+	mac_addr = (struct ether_addr *)explicit_bonded_mac;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_mac_address_set(INVALID_PORT_ID, mac_addr);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_mac_address_set(test_params->slave_port_ids[0],
+			mac_addr);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* NULL MAC address */
+	retval = rte_eth_bond_mac_address_set(test_params->bonded_port_id, NULL);
+	if (retval == 0) {
+		printf("Expected call to failed as NULL MAC specified\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			mac_addr);
+	if (retval != 0) {
+		printf("Failed to set MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* Add 4 slaves to bonded device */
+	for (i = test_params->bonded_slave_count; i < 4; i++) {
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave to bonded device.\n");
+			return -1;
+		}
+	}
+
+	/* Check bonded MAC */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &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;
+	}
+
+	/* Check other slaves MACs */
+	for (i = 0; i < 4; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port mac address not set to that of primary port\n");
+			return -1;
+		}
+	}
+
+	/* test resetting mac address on bonded device */
+	if (rte_eth_bond_mac_address_reset(test_params->bonded_port_id) != 0) {
+		printf("Failed to reset MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+
+		return -1;
+	}
+
+	if (rte_eth_bond_mac_address_reset(test_params->slave_port_ids[0]) == 0) {
+		printf("Reset MAC address on bonded port (%d) unexpectedly\n",
+				test_params->slave_port_ids[1]);
+
+		return -1;
+	}
+
+	/* test resetting mac address on bonded device with no slaves */
+
+	if (remove_slaves_and_stop_bonded_device() != 0)
+		return -1;
+
+	if (rte_eth_bond_mac_address_reset(test_params->bonded_port_id) != 0) {
+		printf("Failed to reset MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+initialize_bonded_device_with_slaves(uint8_t bonding_mode,
+		uint8_t number_of_slaves, uint8_t enable_slave)
+{
+	int retval;
+
+	/* configure bonded device */
+	retval = configure_ethdev(test_params->bonded_port_id, 0);
+	if (retval != 0) {
+		printf("Failed to configure bonding port (%d) in mode %d with (%d) slaves.\n",
+				test_params->bonded_port_id, bonding_mode, number_of_slaves);
+		return -1;
+	}
+
+	while (number_of_slaves > test_params->bonded_slave_count) {
+		/* Add slaves to bonded device */
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave (%d to  bonding port (%d).\n",
+					test_params->bonded_slave_count - 1,
+					test_params->bonded_port_id);
+			return -1;
+		}
+	}
+
+	/* Set link bonding mode  */
+	retval = rte_eth_bond_mode_set(test_params->bonded_port_id, bonding_mode);
+	if (retval != 0) {
+		printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+				test_params->bonded_port_id, bonding_mode);
+		return -1;
+	}
+
+	retval = rte_eth_dev_start(test_params->bonded_port_id);
+	if (retval != 0) {
+		printf("Failed to start bonded pmd eth device.\n");
+		return -1;
+	}
+
+	if (enable_slave)
+		enable_bonded_slaves();
+
+	return 0;
+}
+
+static int
+test_adding_slave_after_bonded_device_started(void)
+{
+	int i;
+
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 0) !=
+			0)
+		return -1;
+
+	/* Enabled slave devices */
+	for (i = 0; i < test_params->bonded_slave_count + 1; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				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_params->bonded_slave_count++;
+
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+generate_test_burst(struct rte_mbuf **pkts_burst, uint16_t burst_size,
+		uint8_t vlan, uint8_t ipv4, uint8_t toggle_dst_mac,
+		uint8_t toggle_ip_addr, uint8_t toggle_udp_port)
+{
+	uint16_t pktlen, generated_burst_size;
+	void *ip_hdr;
+
+	if (toggle_dst_mac)
+		initialize_eth_header(test_params->pkt_eth_hdr,
+				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
+				vlan, vlan_id);
+	else
+		initialize_eth_header(test_params->pkt_eth_hdr,
+				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+				vlan, vlan_id);
+
+
+	if (toggle_udp_port)
+		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+				dst_port_1, 64);
+	else
+		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+				dst_port_0, 64);
+
+	if (ipv4) {
+		if (toggle_ip_addr)
+			pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+					dst_addr_1, pktlen);
+		else
+			pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+					dst_addr_0, pktlen);
+
+		ip_hdr = test_params->pkt_ipv4_hdr;
+	} else {
+		if (toggle_ip_addr)
+			pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr,
+					(uint8_t *)src_ipv6_addr, (uint8_t *)dst_ipv6_addr_1,
+					pktlen);
+		else
+			pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr,
+					(uint8_t *)src_ipv6_addr, (uint8_t *)dst_ipv6_addr_0,
+					pktlen);
+
+		ip_hdr = test_params->pkt_ipv6_hdr;
+	}
+
+	/* Generate burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, vlan, ip_hdr, ipv4,
+			test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size) {
+		printf("Failed to generate packet burst");
+		return -1;
+	}
+
+	return generated_burst_size;
+}
+
+/** Round Robin Mode Tests */
+
+static int
+test_roundrobin_tx_burst(void)
+{
+	int i, burst_size, nb_tx;
+	struct rte_mbuf *pkt_burst[MAX_PKT_BURST];
+	struct rte_eth_stats port_stats;
+
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 2, 1)
+			!= 0)
+		return -1;
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0) != burst_size)
+		return -1;
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst,
+			burst_size);
+	if (nb_tx != burst_size)
+		return -1;
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (port_stats.opackets !=
+				(uint64_t)burst_size / test_params->bonded_slave_count) {
+			printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+					test_params->bonded_port_id,
+					(unsigned int)port_stats.opackets,
+					burst_size / test_params->bonded_slave_count);
+			return -1;
+		}
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst,
+			burst_size);
+	if (nb_tx != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_roundrobin_rx_burst_on_single_slave(void)
+{
+	struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+
+	struct rte_eth_stats port_stats;
+
+	int i, j, nb_rx, burst_size = 25;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1) !=
+			0)
+		return -1;
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(gen_pkt_burst, burst_size, 0, 1, 0, 0, 0) !=
+			burst_size)
+		return -1;
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		/* Add rx data to slave */
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[0], burst_size);
+
+		/* Call rx burst on bonded device */
+		/* Send burst on bonded port */
+		nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+				MAX_PKT_BURST);
+		if (nb_rx != burst_size) {
+			printf("round-robin rx burst failed");
+			return -1;
+		}
+
+		/* Verify bonded device rx count */
+		rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+		if (port_stats.ipackets != (uint64_t)burst_size) {
+			printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+					test_params->bonded_port_id,
+					(unsigned int)port_stats.ipackets, burst_size);
+			return -1;
+		}
+
+
+		/* Verify bonded slave devices rx count */
+		/* Verify slave ports tx stats */
+		for (j = 0; j < test_params->bonded_slave_count; j++) {
+			rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);
+
+			if (i == j) {
+				if (port_stats.ipackets != (uint64_t)burst_size) {
+					printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+							test_params->slave_port_ids[i],
+							(unsigned int)port_stats.ipackets, burst_size);
+					return -1;
+				}
+			} else {
+				if (port_stats.ipackets != 0) {
+					printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+							test_params->slave_port_ids[i],
+							(unsigned int)port_stats.ipackets, 0);
+					return -1;
+				}
+			}
+
+			/* Reset bonded slaves stats */
+			rte_eth_stats_reset(test_params->slave_port_ids[j]);
+		}
+		/* reset bonded device stats */
+		rte_eth_stats_reset(test_params->bonded_port_id);
+	}
+
+	/* free mbufs */
+	for (i = 0; i < MAX_PKT_BURST; i++) {
+		if (gen_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(gen_pkt_burst[i]);
+
+		if (rx_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(rx_pkt_burst[i]);
+	}
+
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT (3)
+
+static int
+test_roundrobin_rx_burst_on_multiple_slaves(void)
+{
+	struct rte_mbuf *gen_pkt_burst[TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT][MAX_PKT_BURST];
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	int burst_size[TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT] = { 15, 13, 36 };
+	int i, nb_rx;
+
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1) !=
+			0)
+		return -1;
+
+	/* Generate test bursts of packets to transmit */
+	for (i = 0; i < TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size[i], 0, 1, 0, 0,
+				0) != burst_size[i])
+			return -1;
+	}
+
+	/* Add rx data to slaves */
+	for (i = 0; i < TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT; i++) {
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size[i]);
+	}
+
+	/* Call rx burst on bonded device */
+	/* Send burst on bonded port */
+	nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+	if (nb_rx != burst_size[0] + burst_size[1] + burst_size[2]) {
+		printf("round-robin rx burst failed (%d != %d)\n", nb_rx,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size[0] + burst_size[1] +
+			burst_size[2])) {
+		printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.ipackets,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+
+	/* Verify bonded slave devices rx counts */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.ipackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.ipackets, burst_size[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[2]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[2],
+				(unsigned int)port_stats.ipackets, burst_size[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.ipackets != 0) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[3],
+				(unsigned int)port_stats.ipackets, 0);
+		return -1;
+	}
+
+	/* free mbufs */
+	for (i = 0; i < MAX_PKT_BURST; i++) {
+		if (rx_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(rx_pkt_burst[i]);
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_roundrobin_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_2;
+
+	int i, retval;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[2], &expected_mac_addr_2);
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1)
+			!= 0)
+		return -1;
+
+	/* Verify that all MACs are the same as first slave added to bonded dev */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	retval = rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[2]);
+	if (retval != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address has changed to that of primary port without stop/start toggle of bonded device\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagate to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_2, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary port\n",
+				test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_2, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary port\n",
+				test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_roundrobin_verify_promiscuous_enable_disable(void)
+{
+	int i, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 1) !=
+			0)
+		return -1;
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(test_params->slave_port_ids[i]);
+		if (promiscuous_en != 1) {
+			printf("slave port (%d) promiscuous mode not enabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_RR_LINK_STATUS_SLAVE_COUNT (4)
+#define TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT (2)
+
+static int
+test_roundrobin_verify_slave_link_status_change_behaviour(void)
+{
+	struct rte_mbuf *tx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_mbuf *gen_pkt_burst[TEST_RR_LINK_STATUS_SLAVE_COUNT][MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+
+	struct rte_eth_stats port_stats;
+	const uint8_t *slaves;
+
+	int i, burst_size, slave_count;
+
+	/* NULL all pointers in array to simplify cleanup */
+	memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst));
+
+	/* Initialize bonded device with TEST_RR_LINK_STATUS_SLAVE_COUNT slaves
+	 * in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN,
+			TEST_RR_LINK_STATUS_SLAVE_COUNT, 1) != 0)
+		return -1;
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != TEST_RR_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of slaves (%d) is not as expected (%d).\n", slave_count,
+				TEST_RR_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != TEST_RR_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, TEST_RR_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	/* Set 2 slaves eth_devs link status to down */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves) != TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT);
+		return -1;
+	}
+
+	burst_size = 21;
+
+	/* Verify that pkts are not sent on slaves with link status down:
+	 *
+	 * 1. Generate test burst of traffic
+	 * 2. Transmit burst on bonded eth_dev
+	 * 3. Verify stats for bonded eth_dev (opackets = burst_size)
+	 * 4. Verify stats for slave eth_devs (s0 = 11, s1 = 0, s2 = 10, s3 = 0)
+	 */
+	if (generate_test_burst(tx_pkt_burst, burst_size, 0, 1, 0, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, tx_pkt_burst,
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != 11) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != 10) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	/* Verify that pkts are not sent on slaves with link status down:
+	 *
+	 * 1. Generate test bursts of traffic
+	 * 2. Add bursts on to virtual eth_devs
+	 * 3. Rx burst on bonded eth_dev, expected (burst_ size *
+	 *    TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT) received
+	 * 4. Verify stats for bonded eth_dev
+	 * 6. Verify stats for slave eth_devs (s0 = 11, s1 = 0, s2 = 10, s3 = 0)
+	 */
+	for (i = 0; i < TEST_RR_LINK_STATUS_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0)
+				!= burst_size) {
+			return -1;
+		}
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size);
+	}
+
+	if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST) != burst_size + burst_size) {
+		printf("rte_eth_rx_burst\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.ipackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* free mbufs */
+	for (i = 0; i < MAX_PKT_BURST; i++) {
+		if (rx_pkt_burst[i] != NULL)
+			rte_pktmbuf_free(rx_pkt_burst[i]);
+
+		if (gen_pkt_burst[1][i] != NULL)
+			rte_pktmbuf_free(gen_pkt_burst[1][i]);
+
+		if (gen_pkt_burst[3][i] != NULL)
+			rte_pktmbuf_free(gen_pkt_burst[1][i]);
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+/** Active Backup Mode Tests */
+
+static int
+test_activebackup_tx_burst(void)
+{
+	int i, retval, pktlen, primary_port, burst_size, generated_burst_size, nb_tx;
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);
+	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+			dst_port_0, 16);
+	pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+			dst_addr_0, pktlen);
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate a burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr,
+			1, test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size)
+		return -1;
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != burst_size)
+		return -1;
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (test_params->slave_port_ids[i] == primary_port) {
+			if (port_stats.opackets != (uint64_t)burst_size) {
+				printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+						test_params->bonded_port_id,
+						(unsigned int)port_stats.opackets,
+						burst_size / test_params->bonded_slave_count);
+				return -1;
+			}
+		} else {
+			if (port_stats.opackets != 0) {
+				printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+						test_params->bonded_port_id,
+						(unsigned int)port_stats.opackets, 0);
+				return -1;
+			}
+		}
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT (4)
+
+static int
+test_activebackup_rx_burst(void)
+{
+	struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+
+	struct rte_eth_stats port_stats;
+
+	int primary_port;
+
+	int i, j, nb_rx, burst_size = 17;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP,
+			TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT, 1)
+			!= 0)
+		return -1;
+
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port < 0) {
+		printf("failed to get primary slave for bonded port (%d)",
+				test_params->bonded_port_id);
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		/* Generate test bursts of packets to transmit */
+		if (generate_test_burst(&gen_pkt_burst[0], burst_size, 0, 1, 0, 0, 0)
+				!= burst_size) {
+			return -1;
+		}
+
+		/* Add rx data to slave */
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[0], burst_size);
+
+		/* Call rx burst on bonded device */
+		nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0,
+				&rx_pkt_burst[0], MAX_PKT_BURST);
+		if (nb_rx < 0) {
+			printf("rte_eth_rx_burst failed\n");
+			return -1;
+		}
+
+		if (test_params->slave_port_ids[i] == primary_port) {
+			/* Verify bonded device rx count */
+			rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+			if (port_stats.ipackets != (uint64_t)burst_size) {
+				printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+						test_params->bonded_port_id,
+						(unsigned int)port_stats.ipackets, burst_size);
+				return -1;
+			}
+
+			/* Verify bonded slave devices rx count */
+			for (j = 0; j < test_params->bonded_slave_count; j++) {
+				rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);
+				if (i == j) {
+					if (port_stats.ipackets != (uint64_t)burst_size) {
+						printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+								test_params->slave_port_ids[i],
+								(unsigned int)port_stats.ipackets, burst_size);
+						return -1;
+					}
+				} else {
+					if (port_stats.ipackets != 0) {
+						printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+								test_params->slave_port_ids[i],
+								(unsigned int)port_stats.ipackets, 0);
+						return -1;
+					}
+				}
+			}
+		} else {
+			for (j = 0; j < test_params->bonded_slave_count; j++) {
+				rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats);
+				if (port_stats.ipackets != 0) {
+					printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+							test_params->slave_port_ids[i],
+							(unsigned int)port_stats.ipackets, 0);
+					return -1;
+				}
+			}
+		}
+
+		/* free mbufs */
+		for (i = 0; i < MAX_PKT_BURST; i++) {
+			if (rx_pkt_burst[i] != NULL) {
+				rte_pktmbuf_free(rx_pkt_burst[i]);
+				rx_pkt_burst[i] = NULL;
+			}
+		}
+
+		/* reset bonded device stats */
+		rte_eth_stats_reset(test_params->bonded_port_id);
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_activebackup_verify_promiscuous_enable_disable(void)
+{
+	int i, primary_port, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP, 4, 1)
+			!= 0)
+		return -1;
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port < 0) {
+		printf("failed to get primary slave for bonded port (%d)",
+				test_params->bonded_port_id);
+	}
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (primary_port == test_params->slave_port_ids[i]) {
+			if (promiscuous_en != 1) {
+				printf("slave port (%d) promiscuous mode not enabled\n",
+						test_params->slave_port_ids[i]);
+				return -1;
+			}
+		} else {
+			if (promiscuous_en != 0) {
+				printf("slave port (%d) promiscuous mode enabled\n",
+						test_params->slave_port_ids[i]);
+				return -1;
+			}
+		}
+
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_activebackup_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1);
+
+	/* Initialize bonded device with 2 slaves in active backup mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP, 2, 1)
+			!= 0)
+		return -1;
+
+	/* Verify that bonded MACs is that of first slave and that the other slave
+	 * MAC hasn't been changed */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	if (rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[1]) != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagated to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0) {
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of bonded port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of bonded port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_activebackup_verify_slave_link_status_change_failover(void)
+{
+	struct rte_mbuf *pkt_burst[TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT][MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	const uint8_t *slaves;
+
+	int i, j, burst_size, slave_count, primary_port;
+
+	burst_size = 21;
+
+	memset(pkt_burst, 0, sizeof(pkt_burst));
+
+	/* Generate packet burst for testing */
+	if (generate_test_burst(&pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP,
+			TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT, 1)
+			!= 0)
+		return -1;
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != 4) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[0])
+		printf("Primary port not as expected");
+
+	/* Bring 2 slaves down and verify active slave count */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves)
+			!= 2) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 2);
+		return -1;
+	}
+
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 1);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 1);
+
+
+	/* Bring primary port down, verify that active slave count is 3 and primary
+	 *  has changed */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[0], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves)
+			!= 3) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 3);
+		return -1;
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[2])
+		printf("Primary port not as expected");
+
+	/* Verify that pkts are sent on new primary slave */
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[0][0], burst_size)
+			!= burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	/* Generate packet burst for testing */
+
+	for (i = 0; i < TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0) !=
+				burst_size)
+			return -1;
+
+		virtual_ethdev_add_mbufs_to_rx_queue(
+			test_params->slave_port_ids[i], &pkt_burst[i][0], burst_size);
+	}
+
+	if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST) != burst_size) {
+		printf("rte_eth_rx_burst\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.ipackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	/* free mbufs */
+
+	for (i = 0; i < TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(pkt_burst[i][j]);
+				pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+/** Balance Mode Tests */
+
+static int
+test_balance_xmit_policy_configuration(void)
+{
+	int retval;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_ACTIVE_BACKUP,
+			2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	/* Invalid port id */
+	retval = rte_eth_bond_xmit_policy_set(INVALID_PORT_ID,
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Set xmit policy on non bonded device */
+	retval = rte_eth_bond_xmit_policy_set(test_params->slave_port_ids[0],
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+	if (rte_eth_bond_xmit_policy_get(test_params->bonded_port_id) !=
+			BALANCE_XMIT_POLICY_LAYER2) {
+		printf("balance xmit policy not as expected.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER23);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+	if (rte_eth_bond_xmit_policy_get(test_params->bonded_port_id) !=
+			BALANCE_XMIT_POLICY_LAYER23) {
+		printf("balance xmit policy not as expected.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER34);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+	if (rte_eth_bond_xmit_policy_get(test_params->bonded_port_id) !=
+			BALANCE_XMIT_POLICY_LAYER34) {
+		printf("balance xmit policy not as expected.\n");
+		return -1;
+	}
+
+	/* Invalid port id */
+	if (rte_eth_bond_xmit_policy_get(INVALID_PORT_ID) >= 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT (2)
+
+static int
+test_balance_l2_tx_burst(void)
+{
+	struct rte_mbuf *pkts_burst[TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT][MAX_PKT_BURST];
+	int burst_size[TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT] = { 10, 15 };
+
+	uint16_t pktlen;
+
+	int retval, i;
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE,
+			TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER2);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);
+	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+			dst_port_0, 16);
+	pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+			dst_addr_0, pktlen);
+
+	/* Generate a burst 1 of packets to transmit */
+	if (generate_packet_burst(test_params->mbuf_pool, &pkts_burst[0][0],
+			test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, 1,
+			test_params->pkt_udp_hdr, burst_size[0]) != burst_size[0])
+		return -1;
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1, 0, 0);
+
+	/* Generate a burst 2 of packets to transmit */
+	if (generate_packet_burst(test_params->mbuf_pool, &pkts_burst[1][0],
+			test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, 1,
+			test_params->pkt_udp_hdr, burst_size[1]) != burst_size[1])
+		return -1;
+
+	/* Send burst 1 on bonded port */
+	for (i = 0; i < TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT; i++) {
+		if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkts_burst[i][0],
+			burst_size[i]) != burst_size[i])
+			return -1;
+	}
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size[0] + burst_size[1])) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				(unsigned int)port_stats.opackets, burst_size[0] + burst_size[1]);
+		return -1;
+	}
+
+
+	/* Verify slave ports tx stats */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.opackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1], (
+						unsigned int)port_stats.opackets, burst_size[1]);
+		return -1;
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkts_burst[0][0],
+			burst_size[0]) != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+balance_l23_tx_burst(uint8_t vlan_enabled, uint8_t ipv4,
+		uint8_t toggle_mac_addr, uint8_t toggle_ip_addr)
+{
+	int retval, i;
+	int burst_size_1, burst_size_2, nb_tx_1, nb_tx_2;
+
+	struct rte_mbuf *pkts_burst_1[MAX_PKT_BURST];
+	struct rte_mbuf *pkts_burst_2[MAX_PKT_BURST];
+
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER23);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+	burst_size_1 = 20;
+	burst_size_2 = 10;
+
+	if (burst_size_1 > MAX_PKT_BURST || burst_size_2 > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkts_burst_1, burst_size_1, vlan_enabled, ipv4,
+			0, 0, 0) != burst_size_1)
+		return -1;
+
+	if (generate_test_burst(pkts_burst_2, burst_size_2, vlan_enabled, ipv4,
+			toggle_mac_addr, toggle_ip_addr, 0) != burst_size_2)
+		return -1;
+
+	/* Send burst 1 on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != burst_size_1)
+		return -1;
+
+	/* Send burst 2 on bonded port */
+	nb_tx_2 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_2,
+			burst_size_2);
+	if (nb_tx_2 != burst_size_2)
+		return -1;
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(nb_tx_1 + nb_tx_2)) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				(unsigned int)port_stats.opackets, nb_tx_1 + nb_tx_2);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_1) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.opackets, nb_tx_1);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_2) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.opackets, nb_tx_2);
+		return -1;
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_l23_tx_burst_ipv4_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(0, 1, 1, 0);
+}
+
+static int
+test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(1, 1, 0, 1);
+}
+
+static int
+test_balance_l23_tx_burst_ipv6_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(0, 0, 0, 1);
+}
+
+static int
+test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr(void)
+{
+	return balance_l23_tx_burst(1, 0, 0, 1);
+}
+
+static int
+test_balance_l23_tx_burst_toggle_mac_addr(void)
+{
+	return balance_l23_tx_burst(0, 0, 1, 0);
+}
+
+static int
+balance_l34_tx_burst(uint8_t vlan_enabled, uint8_t ipv4,
+		uint8_t toggle_mac_addr, uint8_t toggle_ip_addr,
+		uint8_t toggle_udp_port)
+{
+	int retval, i;
+	int burst_size_1, burst_size_2, nb_tx_1, nb_tx_2;
+
+	struct rte_mbuf *pkts_burst_1[MAX_PKT_BURST];
+	struct rte_mbuf *pkts_burst_2[MAX_PKT_BURST];
+
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER34);
+	if (retval != 0) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+	burst_size_1 = 20;
+	burst_size_2 = 10;
+
+	if (burst_size_1 > MAX_PKT_BURST || burst_size_2 > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkts_burst_1, burst_size_1, vlan_enabled, ipv4, 0,
+			0, 0) != burst_size_1)
+		return -1;
+
+	if (generate_test_burst(pkts_burst_2, burst_size_2, vlan_enabled, ipv4,
+			toggle_mac_addr, toggle_ip_addr, toggle_udp_port) != burst_size_2)
+		return -1;
+
+	/* Send burst 1 on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != burst_size_1)
+		return -1;
+
+	/* Send burst 2 on bonded port */
+	nb_tx_2 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_2,
+			burst_size_2);
+	if (nb_tx_2 != burst_size_2)
+		return -1;
+
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(nb_tx_1 + nb_tx_2)) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				(unsigned int)port_stats.opackets, nb_tx_1 + nb_tx_2);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_1) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.opackets, nb_tx_1);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != (uint64_t)nb_tx_2) {
+		printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.opackets, nb_tx_2);
+		return -1;
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1,
+			burst_size_1);
+	if (nb_tx_1 != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_l34_tx_burst_ipv4_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(0, 1, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_ipv4_toggle_udp_port(void)
+{
+	return balance_l34_tx_burst(0, 1, 0, 0, 1);
+}
+
+static int
+test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(1, 1, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_ipv6_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(0, 0, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr(void)
+{
+	return balance_l34_tx_burst(1, 0, 0, 1, 0);
+}
+
+static int
+test_balance_l34_tx_burst_ipv6_toggle_udp_port(void)
+{
+	return balance_l34_tx_burst(0, 0, 0, 0, 1);
+}
+
+#define TEST_BALANCE_RX_BURST_SLAVE_COUNT (3)
+
+static int
+test_balance_rx_burst(void)
+{
+	struct rte_mbuf *gen_pkt_burst[TEST_BALANCE_RX_BURST_SLAVE_COUNT][MAX_PKT_BURST];
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	int burst_size[TEST_BALANCE_RX_BURST_SLAVE_COUNT] = { 10, 5, 30 };
+	int i, j, nb_rx;
+
+	memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 3, 1)
+			!= 0)
+		return -1;
+
+	/* Generate test bursts of packets to transmit */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size[i], 0, 0, 1,
+				0, 0) != burst_size[i])
+			return -1;
+	}
+	/* Add rx data to slaves */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size[i]);
+	}
+
+	/* Call rx burst on bonded device */
+	/* Send burst on bonded port */
+	nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+	if (nb_rx != burst_size[0] + burst_size[1] + burst_size[2]) {
+		printf("balance rx burst failed\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size[0] + burst_size[1] +
+			burst_size[2])) {
+		printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.ipackets,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+
+	/* Verify bonded slave devices rx counts */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.ipackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.ipackets, burst_size[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[2]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[2],
+				(unsigned int)port_stats.ipackets, burst_size[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.ipackets != 0) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[3],
+				(unsigned int)port_stats.ipackets, 0);
+		return -1;
+	}
+
+	/* free mbufs */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (gen_pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(gen_pkt_burst[i][j]);
+				gen_pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_verify_promiscuous_enable_disable(void)
+{
+	int i, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 4, 1) != 0)
+		return -1;
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 1) {
+			printf("slave port (%d) promiscuous mode not enabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_balance_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1);
+
+	/* Initialize bonded device with 2 slaves in active backup mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 2, 1) != 0)
+		return -1;
+
+	/* Verify that bonded MACs is that of first slave and that the other slave
+	 * MAC hasn't been changed */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	if (rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[1]) != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_0, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagated to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of primary port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of primary port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of bonded port\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr);
+	if (memcmp(&bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("slave port (%d) mac address not set to that of bonded port\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define TEST_BALANCE_LINK_STATUS_SLAVE_COUNT (4)
+
+static int
+test_balance_verify_slave_link_status_change_behaviour(void)
+{
+	struct rte_mbuf *pkt_burst[TEST_BALANCE_LINK_STATUS_SLAVE_COUNT][MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	const uint8_t *slaves;
+
+	int i, j, burst_size, slave_count;
+
+	memset(pkt_burst, 0, sizeof(pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE,
+			TEST_BALANCE_LINK_STATUS_SLAVE_COUNT, 1) != 0)
+		return -1;
+
+	if (rte_eth_bond_xmit_policy_set(test_params->bonded_port_id,
+			BALANCE_XMIT_POLICY_LAYER2)) {
+		printf("Failed to set balance xmit policy.\n");
+		return -1;
+	}
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != TEST_BALANCE_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of slaves (%d) is not as expected (%d).\n", slave_count,
+				TEST_BALANCE_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != TEST_BALANCE_LINK_STATUS_SLAVE_COUNT) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, TEST_BALANCE_LINK_STATUS_SLAVE_COUNT);
+		return -1;
+	}
+
+	/* Set 2 slaves link status to down */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves) != 2) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 2);
+		return -1;
+	}
+
+	/* Send to sets of packet burst and verify that they are balanced across
+	 *  slaves */
+	burst_size = 21;
+
+	if (generate_test_burst(&pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (generate_test_burst(&pkt_burst[1][0], burst_size, 0, 1, 1, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[0][0],
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[1][0],
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->bonded_port_id, (int)port_stats.opackets,
+				burst_size + burst_size);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->slave_port_ids[0], (int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->slave_port_ids[2], (int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	/* verify that all packets get send on primary slave when no other slaves
+	 * are available */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[2], 0);
+
+	if (rte_eth_bond_active_slaves_get(test_params->bonded_port_id, &slaves) !=
+			1) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 1);
+		return -1;
+	}
+
+	if (generate_test_burst(&pkt_burst[1][0], burst_size, 0, 1, 1, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[1][0],
+			burst_size) != burst_size) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size + burst_size +
+			burst_size)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->bonded_port_id, (int)port_stats.opackets,
+				burst_size + burst_size + burst_size);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d).\n",
+				test_params->slave_port_ids[0], (int)port_stats.opackets,
+				burst_size + burst_size);
+		return -1;
+	}
+
+
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[0], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 1);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[2], 1);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 1);
+
+	for (i = 0; i < TEST_BALANCE_LINK_STATUS_SLAVE_COUNT; i++) {
+		if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0) !=
+				burst_size)
+			return -1;
+
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&pkt_burst[i][0], burst_size);
+	}
+
+
+
+	/* Verify that pkts are not received on slaves with link status down */
+
+	rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size * 3)) {
+		printf("(%d) port_stats.ipackets (%d) not as expected (%d)\n",
+				test_params->bonded_port_id, (int)port_stats.ipackets,
+				burst_size * 3);
+		return -1;
+	}
+
+	/* free mbufs allocate for rx testing */
+	for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(pkt_burst[i][j]);
+				pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+/** Broadcast Mode Tests */
+
+static int
+test_broadcast_tx_burst(void)
+{
+	int i, pktlen, retval, burst_size, generated_burst_size, nb_tx;
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+
+	struct rte_eth_stats port_stats;
+
+	retval = initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST, 2, 1);
+	if (retval != 0) {
+		printf("Failed to initialize_bonded_device_with_slaves.\n");
+		return -1;
+	}
+
+	initialize_eth_header(test_params->pkt_eth_hdr,
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 0, 0);
+
+	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+			dst_port_0, 16);
+	pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+			dst_addr_0, pktlen);
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate a burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr,
+			1, test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size)
+		return -1;
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != burst_size * test_params->bonded_slave_count) {
+		printf("Bonded Port (%d) rx burst failed, packets transmitted value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id,
+				nb_tx, burst_size);
+		return -1;
+	}
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size *
+			test_params->bonded_slave_count) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+	}
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (port_stats.opackets != (uint64_t)burst_size) {
+			printf("Slave Port (%d) opackets value (%u) not as expected (%d)\n",
+					test_params->bonded_port_id,
+					(unsigned int)port_stats.opackets, burst_size);
+		}
+	}
+
+	/* Put all slaves down and try and transmit */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 0);
+	}
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst,
+			burst_size);
+	if (nb_tx != 0)
+		return -1;
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define BROADCAST_RX_BURST_NUM_OF_SLAVES (3)
+
+static int
+test_broadcast_rx_burst(void)
+{
+	struct rte_mbuf *gen_pkt_burst[BROADCAST_RX_BURST_NUM_OF_SLAVES][MAX_PKT_BURST];
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	int burst_size[BROADCAST_RX_BURST_NUM_OF_SLAVES] = { 10, 5, 30 };
+	int i, j, nb_rx;
+
+	memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST, 3, 1) != 0)
+		return -1;
+
+
+	/* Generate test bursts of packets to transmit */
+	for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) {
+		if (generate_test_burst(&gen_pkt_burst[i][0], burst_size[i], 0, 0, 1, 0,
+				0) != burst_size[i])
+			return -1;
+	}
+
+	/* Add rx data to slave 0 */
+	for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) {
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&gen_pkt_burst[i][0], burst_size[i]);
+	}
+
+
+	/* Call rx burst on bonded device */
+	/* Send burst on bonded port */
+	nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST);
+	if (nb_rx != burst_size[0] + burst_size[1] + burst_size[2]) {
+		printf("round-robin rx burst failed");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size[0] + burst_size[1] +
+			burst_size[2])) {
+		printf("Bonded Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.ipackets,
+				burst_size[0] + burst_size[1] + burst_size[2]);
+		return -1;
+	}
+
+
+	/* Verify bonded slave devices rx counts */
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[0]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[0],
+				(unsigned int)port_stats.ipackets, burst_size[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[1]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[1],
+				(unsigned int)port_stats.ipackets, burst_size[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.ipackets != (uint64_t)burst_size[2]) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[2],
+				(unsigned int)port_stats.ipackets,
+				burst_size[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.ipackets != 0) {
+		printf("Slave Port (%d) ipackets value (%u) not as expected (%d)\n",
+				test_params->slave_port_ids[3],
+				(unsigned int)port_stats.ipackets, 0);
+		return -1;
+	}
+
+	/* free mbufs allocate for rx testing */
+	for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (gen_pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(gen_pkt_burst[i][j]);
+				gen_pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_broadcast_verify_promiscuous_enable_disable(void)
+{
+	int i, promiscuous_en;
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BALANCE, 4, 1) != 0)
+		return -1;
+
+	rte_eth_promiscuous_enable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 1) {
+		printf("Port (%d) promiscuous mode not enabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 1) {
+			printf("slave port (%d) promiscuous mode not enabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	rte_eth_promiscuous_disable(test_params->bonded_port_id);
+
+	promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id);
+	if (promiscuous_en != 0) {
+		printf("Port (%d) promiscuous mode not disabled\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		promiscuous_en = rte_eth_promiscuous_get(
+				test_params->slave_port_ids[i]);
+		if (promiscuous_en != 0) {
+			printf("slave port (%d) promiscuous mode not disabled\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_broadcast_verify_mac_assignment(void)
+{
+	struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1;
+
+	int i, retval;
+
+	rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0);
+	rte_eth_macaddr_get(test_params->slave_port_ids[2], &expected_mac_addr_1);
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST, 4, 1) != 0)
+		return -1;
+
+	/* Verify that all MACs are the same as first slave added to bonded
+	 * device */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* change primary and verify that MAC addresses haven't changed */
+	retval = rte_eth_bond_primary_set(test_params->bonded_port_id,
+			test_params->slave_port_ids[2]);
+	if (retval != 0) {
+		printf("Failed to set bonded port (%d) primary port to (%d)\n",
+				test_params->bonded_port_id, test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_0, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address has changed to that of primary port without stop/start toggle of bonded device\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* stop / start bonded device and verify that primary MAC address is
+	 * propagated to bonded device and slaves */
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	if (rte_eth_dev_start(test_params->bonded_port_id) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(&expected_mac_addr_1, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary port\n",
+				test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(&expected_mac_addr_1, &read_mac_addr,
+				sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Set explicit MAC address */
+	if (rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			(struct ether_addr *)bonded_mac) != 0)
+		return -1;
+
+	rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+	if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+		printf("bonded port (%d) mac address not set to that of new primary port\n",
+				test_params->slave_port_ids[i]);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(bonded_mac, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port (%d) mac address not set to that of new primary port\n",
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+#define BROADCAST_LINK_STATUS_NUM_OF_SLAVES (4)
+static int
+test_broadcast_verify_slave_link_status_change_behaviour(void)
+{
+	struct rte_mbuf *pkt_burst[BROADCAST_LINK_STATUS_NUM_OF_SLAVES][MAX_PKT_BURST];
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL };
+	struct rte_eth_stats port_stats;
+
+	const uint8_t *slaves;
+
+	int i, j, burst_size, slave_count;
+
+	memset(pkt_burst, 0, sizeof(pkt_burst));
+
+	/* Initialize bonded device with 4 slaves in round robin mode */
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_BROADCAST,
+			BROADCAST_LINK_STATUS_NUM_OF_SLAVES, 1) != 0)
+		return -1;
+
+	/* Verify Current Slaves Count /Active Slave Count is */
+	slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, &slaves);
+	if (slave_count != 4) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 4);
+		return -1;
+	}
+
+	/* Set 2 slaves link status to down */
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[1], 0);
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[3], 0);
+
+	slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id,
+			&slaves);
+	if (slave_count != 2) {
+		printf("Number of active slaves (%d) is not as expected (%d).\n",
+				slave_count, 2);
+		return -1;
+	}
+
+	for (i = 0; i < test_params->bonded_slave_count; i++)
+		rte_eth_stats_reset(test_params->slave_port_ids[i]);
+
+	/* Verify that pkts are not sent on slaves with link status down */
+	burst_size = 21;
+
+	if (generate_test_burst(&pkt_burst[0][0], burst_size, 0, 0, 1, 0, 0) !=
+			burst_size) {
+		printf("generate_test_burst failed\n");
+		return -1;
+	}
+
+	if (rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt_burst[0][0],
+			burst_size) != (burst_size * slave_count)) {
+		printf("rte_eth_tx_burst failed\n");
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)(burst_size * slave_count)) {
+		printf("(%d) port_stats.opackets (%d) not as expected (%d)\n",
+				test_params->bonded_port_id, (int)port_stats.opackets,
+				burst_size * slave_count);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[1]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[2]);
+		return -1;
+	}
+
+	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
+	if (port_stats.opackets != 0) {
+		printf("(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[3]);
+		return -1;
+	}
+
+	for (i = 0; i < BROADCAST_LINK_STATUS_NUM_OF_SLAVES; i++) {
+		if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 0, 1, 0, 0) !=
+				burst_size) {
+			return -1;
+		}
+
+		virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i],
+				&pkt_burst[i][0], burst_size);
+	}
+
+	/* Verify that pkts are not received on slaves with link status down */
+
+	if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst,
+			MAX_PKT_BURST) !=
+			burst_size + burst_size) {
+		printf("rte_eth_rx_burst\n");
+		return -1;
+	}
+
+	/* Verify bonded device rx count */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.ipackets != (uint64_t)(burst_size + burst_size)) {
+		printf("(%d) port_stats.ipackets not as expected\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* free mbufs allocate for rx testing */
+	for (i = 0; i < BROADCAST_LINK_STATUS_NUM_OF_SLAVES; i++) {
+		for (j = 0; j < MAX_PKT_BURST; j++) {
+			if (pkt_burst[i][j] != NULL) {
+				rte_pktmbuf_free(pkt_burst[i][j]);
+				pkt_burst[i][j] = NULL;
+			}
+		}
+	}
+
+	/* Clean up and remove slaves from bonded device */
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_reconfigure_bonded_device(void)
+{
+	test_params->nb_rx_q = 4;
+	test_params->nb_tx_q = 4;
+
+	if (configure_ethdev(test_params->bonded_port_id, 0)  != 0) {
+		printf("failed to reconfigure bonded device");
+		return -1;
+	}
+
+
+	test_params->nb_rx_q = 2;
+	test_params->nb_tx_q = 2;
+
+	if (configure_ethdev(test_params->bonded_port_id, 0)  != 0) {
+		printf("failed to reconfigure bonded device with less rx/tx queues");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+test_close_bonded_device(void)
+{
+	rte_eth_dev_close(test_params->bonded_port_id);
+	return 0;
+}
+
+static int
+testsuite_teardown(void)
+{
+	if (test_params->pkt_eth_hdr != NULL)
+		free(test_params->pkt_eth_hdr);
+
+	return 0;
+}
+
+struct unittest {
+	int (*test_function)(void);
+	const char *success_msg;
+	const char *fail_msg;
+};
+
+struct unittest_suite {
+	int (*setup_function)(void);
+	int (*teardown_function)(void);
+	struct unittest unittests[];
+};
+
+static struct unittest_suite link_bonding_test_suite  = {
+	.setup_function = test_setup,
+	.teardown_function = testsuite_teardown,
+	.unittests = {
+		{ test_create_bonded_device, "test_create_bonded_device succeeded",
+			"test_create_bonded_device failed" },
+		{ test_create_bonded_device_with_invalid_params,
+			"test_create_bonded_device_with_invalid_params succeeded",
+			"test_create_bonded_device_with_invalid_params failed" },
+		{ test_add_slave_to_bonded_device,
+			"test_add_slave_to_bonded_device succeeded",
+			"test_add_slave_to_bonded_device failed" },
+		{ test_add_slave_to_invalid_bonded_device,
+			"test_add_slave_to_invalid_bonded_device succeeded",
+			"test_add_slave_to_invalid_bonded_device failed" },
+		{ test_remove_slave_from_bonded_device,
+			"test_remove_slave_from_bonded_device succeeded ",
+			"test_remove_slave_from_bonded_device failed" },
+		{ test_remove_slave_from_invalid_bonded_device,
+			"test_remove_slave_from_invalid_bonded_device succeeded",
+			"test_remove_slave_from_invalid_bonded_device failed" },
+		{ test_get_slaves_from_bonded_device,
+			"test_get_slaves_from_bonded_device succeeded",
+			"test_get_slaves_from_bonded_device failed" },
+		{ test_add_already_bonded_slave_to_bonded_device,
+			"test_add_already_bonded_slave_to_bonded_device succeeded",
+			"test_add_already_bonded_slave_to_bonded_device failed" },
+		{ test_add_remove_multiple_slaves_to_from_bonded_device,
+			"test_add_remove_multiple_slaves_to_from_bonded_device succeeded",
+			"test_add_remove_multiple_slaves_to_from_bonded_device failed" },
+		{ test_start_bonded_device,
+			"test_start_bonded_device succeeded",
+			"test_start_bonded_device failed" },
+		{ test_stop_bonded_device,
+			"test_stop_bonded_device succeeded",
+			"test_stop_bonded_device failed" },
+		{ test_set_bonding_mode,
+			"test_set_bonding_mode succeeded",
+			"test_set_bonding_mode failed" },
+		{ test_set_primary_slave,
+			"test_set_primary_slave succeeded",
+			"test_set_primary_slave failed" },
+		{ test_set_explicit_bonded_mac,
+			"test_set_explicit_bonded_mac succeeded",
+			"test_set_explicit_bonded_mac failed" },
+		{ test_adding_slave_after_bonded_device_started,
+			"test_adding_slave_after_bonded_device_started succeeded",
+			"test_adding_slave_after_bonded_device_started failed" },
+		{ test_roundrobin_tx_burst,
+			"test_roundrobin_tx_burst succeeded",
+			"test_roundrobin_tx_burst failed" },
+		{ test_roundrobin_rx_burst_on_single_slave,
+			"test_roundrobin_rx_burst_on_single_slave succeeded",
+			"test_roundrobin_rx_burst_on_single_slave failed" },
+		{ test_roundrobin_rx_burst_on_multiple_slaves,
+			"test_roundrobin_rx_burst_on_multiple_slaves succeeded",
+			"test_roundrobin_rx_burst_on_multiple_slaves failed" },
+		{ test_roundrobin_verify_promiscuous_enable_disable,
+			"test_roundrobin_verify_promiscuous_enable_disable succeeded",
+			"test_roundrobin_verify_promiscuous_enable_disable failed" },
+		{ test_roundrobin_verify_mac_assignment,
+			"test_roundrobin_verify_mac_assignment succeeded",
+			"test_roundrobin_verify_mac_assignment failed" },
+		{ test_roundrobin_verify_slave_link_status_change_behaviour,
+			"test_roundrobin_verify_slave_link_status_change_behaviour succeeded",
+			"test_roundrobin_verify_slave_link_status_change_behaviour failed" },
+		{ test_activebackup_tx_burst,
+			"test_activebackup_tx_burst succeeded",
+			"test_activebackup_tx_burst failed" },
+		{ test_activebackup_rx_burst,
+			"test_activebackup_rx_burst succeeded",
+			"test_activebackup_rx_burst failed" },
+		{ test_activebackup_verify_promiscuous_enable_disable,
+			"test_activebackup_verify_promiscuous_enable_disable succeeded",
+			"test_activebackup_verify_promiscuous_enable_disable failed" },
+		{ test_activebackup_verify_mac_assignment,
+			"test_activebackup_verify_mac_assignment succeeded",
+			"test_activebackup_verify_mac_assignment failed" },
+		{ test_activebackup_verify_slave_link_status_change_failover,
+			"test_activebackup_verify_slave_link_status_change_failover succeeded",
+			"test_activebackup_verify_slave_link_status_change_failover failed" },
+		{ test_balance_xmit_policy_configuration,
+			"test_balance_xmit_policy_configuration succeeded",
+			"test_balance_xmit_policy_configuration failed" },
+		{ test_balance_l2_tx_burst,
+			"test_balance_l2_tx_burst succeeded",
+			"test_balance_l2_tx_burst failed" },
+		{ test_balance_l23_tx_burst_ipv4_toggle_ip_addr,
+			"test_balance_l23_tx_burst_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr,
+			"test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_ipv6_toggle_ip_addr,
+			"test_balance_l23_tx_burst_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr,
+			"test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l23_tx_burst_toggle_mac_addr,
+			"test_balance_l23_tx_burst_toggle_mac_addr succeeded",
+			"test_balance_l23_tx_burst_toggle_mac_addr failed" },
+		{ test_balance_l34_tx_burst_ipv4_toggle_ip_addr,
+			"test_balance_l34_tx_burst_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_ipv4_toggle_udp_port,
+			"test_balance_l34_tx_burst_ipv4_toggle_udp_port succeeded",
+			"test_balance_l34_tx_burst_ipv4_toggle_udp_port failed" },
+		{ test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr,
+			"test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_ipv6_toggle_ip_addr,
+			"test_balance_l34_tx_burst_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr,
+			"test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr succeeded",
+			"test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr failed" },
+		{ test_balance_l34_tx_burst_ipv6_toggle_udp_port,
+			"test_balance_l34_tx_burst_ipv6_toggle_udp_port succeeded",
+			"test_balance_l34_tx_burst_ipv6_toggle_udp_port failed" },
+		{ test_balance_rx_burst,
+			"test_balance_rx_burst succeeded",
+			"test_balance_rx_burst failed" },
+		{ test_balance_verify_promiscuous_enable_disable,
+			"test_balance_verify_promiscuous_enable_disable succeeded",
+			"test_balance_verify_promiscuous_enable_disable failed" },
+		{ test_balance_verify_mac_assignment,
+			"test_balance_verify_mac_assignment succeeded",
+			"test_balance_verify_mac_assignment failed" },
+		{ test_balance_verify_slave_link_status_change_behaviour,
+			"test_balance_verify_slave_link_status_change_behaviour succeeded",
+			"test_balance_verify_slave_link_status_change_behaviour failed" },
+		{ test_broadcast_tx_burst,
+			"test_broadcast_tx_burst succeeded",
+			"test_broadcast_tx_burst failed" },
+		{ test_broadcast_rx_burst,
+			"test_broadcast_rx_burst succeeded",
+			"test_broadcast_rx_burst failed" },
+		{ test_broadcast_verify_promiscuous_enable_disable,
+			"test_broadcast_verify_promiscuous_enable_disable succeeded",
+			"test_broadcast_verify_promiscuous_enable_disable failed" },
+		{ test_broadcast_verify_mac_assignment,
+			"test_broadcast_verify_mac_assignment succeeded",
+			"test_broadcast_verify_mac_assignment failed" },
+		{ test_broadcast_verify_slave_link_status_change_behaviour,
+			"test_broadcast_verify_slave_link_status_change_behaviour succeeded",
+			"test_broadcast_verify_slave_link_status_change_behaviour failed" },
+		{ test_reconfigure_bonded_device,
+			"test_reconfigure_bonded_device succeeded",
+			"test_reconfigure_bonded_device failed" },
+		{ test_close_bonded_device,
+			"test_close_bonded_device succeeded",
+			"test_close_bonded_device failed" },
+
+		{ NULL , NULL, NULL } /**< NULL terminate unit test array */
+	}
+};
+
+
+int
+test_link_bonding(void)
+{
+	int i = 0;
+
+	if (link_bonding_test_suite.setup_function) {
+		if (link_bonding_test_suite.setup_function() != 0)
+			return -1;
+	}
+
+	while (link_bonding_test_suite.unittests[i].test_function) {
+		if (link_bonding_test_suite.unittests[i].test_function() == 0) {
+			printf("%s", link_bonding_test_suite.unittests[i].success_msg ?
+					link_bonding_test_suite.unittests[i].success_msg :
+					"unit test succeeded");
+		} else {
+			printf("%s", link_bonding_test_suite.unittests[i].fail_msg ?
+					link_bonding_test_suite.unittests[i].fail_msg :
+					"unit test failed");
+			return -1;
+		}
+		printf("\n");
+		i++;
+	}
+
+	if (link_bonding_test_suite.teardown_function) {
+		if (link_bonding_test_suite.teardown_function() != 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
new file mode 100644
index 0000000..f2ef084
--- /dev/null
+++ b/app/test/virtual_pmd.c
@@ -0,0 +1,574 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_memory.h>
+
+#include "virtual_pmd.h"
+
+#define MAX_PKT_BURST 512
+
+static const char *virtual_ethdev_driver_name = "Virtual PMD";
+
+struct virtual_ethdev_private {
+	struct rte_eth_stats eth_stats;
+
+	struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST];
+	int rx_pkt_burst_len;
+};
+
+struct virtual_ethdev_queue {
+	int port_id;
+	int queue_id;
+};
+
+static int
+virtual_ethdev_start_success(struct rte_eth_dev *eth_dev __rte_unused)
+{
+	eth_dev->data->dev_started = 1;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev __rte_unused)
+{
+	eth_dev->data->dev_started = 0;
+
+	return -1;
+}
+static void  virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused)
+{
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_started = 0;
+}
+
+static void
+virtual_ethdev_close(struct rte_eth_dev *dev __rte_unused)
+{}
+
+static int
+virtual_ethdev_configure_success(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static int
+virtual_ethdev_configure_fail(struct rte_eth_dev *dev __rte_unused)
+{
+	return -1;
+}
+
+static void
+virtual_ethdev_info_get(struct rte_eth_dev *dev __rte_unused,
+		struct rte_eth_dev_info *dev_info)
+{
+	dev_info->driver_name = virtual_ethdev_driver_name;
+	dev_info->max_mac_addrs = 1;
+
+	dev_info->max_rx_pktlen = (uint32_t)2048;
+
+	dev_info->max_rx_queues = (uint16_t)128;
+	dev_info->max_tx_queues = (uint16_t)512;
+
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static int
+virtual_ethdev_rx_queue_setup_success(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id, uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	struct virtual_ethdev_queue *rx_q;
+
+	rx_q = (struct virtual_ethdev_queue *)rte_zmalloc_socket(NULL,
+			sizeof(struct virtual_ethdev_queue), 0, socket_id);
+
+	if (rx_q == NULL)
+		return -1;
+
+	rx_q->port_id = dev->data->port_id;
+	rx_q->queue_id = rx_queue_id;
+
+	dev->data->rx_queues[rx_queue_id] = rx_q;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_rx_queue_setup_fail(struct rte_eth_dev *dev __rte_unused,
+		uint16_t rx_queue_id __rte_unused, uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool __rte_unused)
+{
+	return -1;
+}
+
+static int
+virtual_ethdev_tx_queue_setup_success(struct rte_eth_dev *dev,
+		uint16_t tx_queue_id, uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct virtual_ethdev_queue *tx_q;
+
+	tx_q = (struct virtual_ethdev_queue *)rte_zmalloc_socket(NULL,
+			sizeof(struct virtual_ethdev_queue), 0, socket_id);
+
+	if (tx_q == NULL)
+		return -1;
+
+	tx_q->port_id = dev->data->port_id;
+	tx_q->queue_id = tx_queue_id;
+
+	dev->data->tx_queues[tx_queue_id] = tx_q;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_tx_queue_setup_fail(struct rte_eth_dev *dev __rte_unused,
+		uint16_t tx_queue_id __rte_unused, uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	return -1;
+}
+
+static void
+virtual_ethdev_rx_queue_release(void *q __rte_unused)
+{
+}
+
+static void
+virtual_ethdev_tx_queue_release(void *q __rte_unused)
+{
+}
+
+static int
+virtual_ethdev_link_update_success(struct rte_eth_dev *bonded_eth_dev,
+		int wait_to_complete __rte_unused)
+{
+	if (!bonded_eth_dev->data->dev_started)
+		bonded_eth_dev->data->dev_link.link_status = 0;
+
+	return 0;
+}
+
+static int
+virtual_ethdev_link_update_fail(struct rte_eth_dev *bonded_eth_dev __rte_unused,
+		int wait_to_complete __rte_unused)
+{
+	return -1;
+}
+
+static void
+virtual_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct virtual_ethdev_private *dev_private = dev->data->dev_private;
+
+	if (stats)
+		rte_memcpy(stats, &dev_private->eth_stats, sizeof(*stats));
+}
+
+static void
+virtual_ethdev_stats_reset(struct rte_eth_dev *dev)
+{
+	struct virtual_ethdev_private *dev_private = dev->data->dev_private;
+
+	dev_private->rx_pkt_burst_len = 0;
+
+	/* Reset internal statistics */
+	memset(&dev_private->eth_stats, 0, sizeof(dev_private->eth_stats));
+}
+
+static void
+virtual_ethdev_promiscuous_mode_enable(struct rte_eth_dev *dev __rte_unused)
+{}
+
+static void
+virtual_ethdev_promiscuous_mode_disable(struct rte_eth_dev *dev __rte_unused)
+{}
+
+
+static struct eth_dev_ops virtual_ethdev_default_dev_ops = {
+		.dev_configure = virtual_ethdev_configure_success,
+		.dev_start = virtual_ethdev_start_success,
+		.dev_stop = virtual_ethdev_stop,
+		.dev_close = virtual_ethdev_close,
+		.dev_infos_get = virtual_ethdev_info_get,
+		.rx_queue_setup = virtual_ethdev_rx_queue_setup_success,
+		.tx_queue_setup = virtual_ethdev_tx_queue_setup_success,
+		.rx_queue_release = virtual_ethdev_rx_queue_release,
+		.tx_queue_release = virtual_ethdev_tx_queue_release,
+		.link_update = virtual_ethdev_link_update_success,
+		.stats_get = virtual_ethdev_stats_get,
+		.stats_reset = virtual_ethdev_stats_reset,
+		.promiscuous_enable = virtual_ethdev_promiscuous_mode_enable,
+		.promiscuous_disable = virtual_ethdev_promiscuous_mode_disable
+};
+
+
+void
+virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->dev_start = virtual_ethdev_start_success;
+	else
+		vrtl_eth_dev->dev_ops->dev_start = virtual_ethdev_start_fail;
+
+}
+
+void
+virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->dev_configure = virtual_ethdev_configure_success;
+	else
+		vrtl_eth_dev->dev_ops->dev_configure = virtual_ethdev_configure_fail;
+}
+
+void
+virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->rx_queue_setup =
+				virtual_ethdev_rx_queue_setup_success;
+	else
+		vrtl_eth_dev->dev_ops->rx_queue_setup =
+				virtual_ethdev_rx_queue_setup_fail;
+}
+
+void
+virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->tx_queue_setup =
+				virtual_ethdev_tx_queue_setup_success;
+	else
+		vrtl_eth_dev->dev_ops->tx_queue_setup =
+				virtual_ethdev_tx_queue_setup_fail;
+}
+
+void
+virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->dev_ops->link_update = virtual_ethdev_link_update_success;
+	else
+		vrtl_eth_dev->dev_ops->link_update = virtual_ethdev_link_update_fail;
+}
+
+
+static uint16_t
+virtual_ethdev_rx_burst_success(void *queue __rte_unused,
+							 struct rte_mbuf **bufs,
+							 uint16_t nb_pkts)
+{
+	struct rte_eth_dev *vrtl_eth_dev;
+	struct virtual_ethdev_queue *pq_map;
+	struct virtual_ethdev_private *dev_private;
+
+	int i;
+
+	pq_map = (struct virtual_ethdev_queue *)queue;
+
+	vrtl_eth_dev = &rte_eth_devices[pq_map->port_id];
+
+	dev_private = vrtl_eth_dev->data->dev_private;
+
+	if (dev_private->rx_pkt_burst_len > 0) {
+		if (dev_private->rx_pkt_burst_len < nb_pkts) {
+
+			for (i = 0; i < dev_private->rx_pkt_burst_len; i++) {
+				bufs[i] = dev_private->rx_pkt_burst[i];
+				dev_private->rx_pkt_burst[i] = NULL;
+			}
+
+			dev_private->eth_stats.ipackets = dev_private->rx_pkt_burst_len;
+		}
+		/* reset private burst values */
+		dev_private->rx_pkt_burst_len = 0;
+	}
+
+	return dev_private->eth_stats.ipackets;
+}
+
+static uint16_t
+virtual_ethdev_rx_burst_fail(void *queue __rte_unused,
+							 struct rte_mbuf **bufs __rte_unused,
+							 uint16_t nb_pkts __rte_unused)
+{
+	return 0;
+}
+
+static uint16_t
+virtual_ethdev_tx_burst_success(void *queue,
+							 struct rte_mbuf **bufs __rte_unused,
+							 uint16_t nb_pkts)
+{
+	struct rte_eth_dev *vrtl_eth_dev;
+	struct virtual_ethdev_queue *tx_q;
+	struct virtual_ethdev_private *dev_private;
+	int i;
+
+	tx_q = (struct virtual_ethdev_queue *)queue;
+
+	vrtl_eth_dev = &rte_eth_devices[tx_q->port_id];
+
+	if (vrtl_eth_dev->data->dev_link.link_status) {
+		dev_private = vrtl_eth_dev->data->dev_private;
+		dev_private->eth_stats.opackets += nb_pkts;
+
+		return nb_pkts;
+	}
+
+	/* free packets in burst */
+	for (i = 0; i < nb_pkts; i++) {
+		if (bufs[i] != NULL)
+			rte_pktmbuf_free(bufs[i]);
+
+		bufs[i] = NULL;
+	}
+
+	return 0;
+}
+
+
+static uint16_t
+virtual_ethdev_tx_burst_fail(void *queue __rte_unused,
+		struct rte_mbuf **bufs __rte_unused, uint16_t nb_pkts __rte_unused)
+{
+	return 0;
+}
+
+
+void
+virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_success;
+	else
+		vrtl_eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_fail;
+}
+
+
+void
+virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success)
+{
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	if (success)
+		vrtl_eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_success;
+	else
+		vrtl_eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_fail;
+}
+
+
+void
+virtual_ethdev_simulate_link_status_interrupt(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;
+
+	_rte_eth_dev_callback_process(vrtl_eth_dev, RTE_ETH_EVENT_INTR_LSC);
+}
+
+
+
+void
+virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id,
+		struct rte_mbuf **pkt_burst, int burst_length)
+{
+	struct virtual_ethdev_private *dev_private = NULL;
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
+
+	int i;
+
+	dev_private = vrtl_eth_dev->data->dev_private;
+
+	for (i = 0; i < burst_length; i++)
+		dev_private->rx_pkt_burst[i] = pkt_burst[i];
+
+	dev_private->rx_pkt_burst_len = burst_length;
+}
+
+static uint8_t
+get_number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; i < RTE_MAX_MEMSEG && ms[i].addr != NULL; i++) {
+		if (sockets < ms[i].socket_id)
+			sockets = ms[i].socket_id;
+	}
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+}
+
+
+int
+virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
+		uint8_t socket_id)
+{
+	struct rte_pci_device *pci_dev = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct eth_driver *eth_drv = NULL;
+	struct rte_pci_driver *pci_drv = NULL;
+	struct eth_dev_ops *dev_ops = NULL;
+	struct rte_pci_id *id_table = NULL;
+	struct virtual_ethdev_private *dev_private = NULL;
+
+
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (dev_private) data
+	 */
+
+	if (socket_id >= get_number_of_sockets())
+		goto err;
+
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, socket_id);
+	if (pci_dev == NULL)
+		goto err;
+
+	eth_drv = rte_zmalloc_socket(name, sizeof(*eth_drv), 0, socket_id);
+	if (eth_drv == NULL)
+		goto err;
+
+	pci_drv = rte_zmalloc_socket(name, sizeof(*pci_drv), 0, socket_id);
+	if (pci_drv == NULL)
+		goto err;
+
+	dev_ops = rte_zmalloc_socket(name, sizeof(*dev_ops), 0, socket_id);
+	if (dev_ops == NULL)
+		goto err;
+
+	id_table = rte_zmalloc_socket(name, sizeof(*id_table), 0, socket_id);
+	if (id_table == NULL)
+		goto err;
+
+	dev_private = rte_zmalloc_socket(name, sizeof(*dev_private), 0, socket_id);
+	if (dev_private == NULL)
+		goto err;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate();
+	if (eth_dev == NULL)
+		goto err;
+
+	pci_dev->numa_node = socket_id;
+	pci_drv->name = virtual_ethdev_driver_name;
+	pci_drv->id_table = id_table;
+
+	eth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);
+	eth_dev->driver = eth_drv;
+
+	eth_dev->data->nb_rx_queues = (uint16_t)1;
+	eth_dev->data->nb_tx_queues = (uint16_t)1;
+
+	TAILQ_INIT(&(eth_dev->callbacks));
+
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_link.link_speed = ETH_LINK_SPEED_10000;
+	eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX;
+
+	eth_dev->data->mac_addrs = rte_zmalloc(name, ETHER_ADDR_LEN, 0);
+	if (eth_dev->data->mac_addrs == NULL)
+		goto err;
+
+	memcpy(eth_dev->data->mac_addrs, mac_addr,
+			sizeof(*eth_dev->data->mac_addrs));
+	eth_dev->data->mac_addrs->addr_bytes[5] = eth_dev->data->port_id;
+
+	eth_dev->data->dev_started = 0;
+	eth_dev->data->promiscuous = 0;
+	eth_dev->data->scattered_rx = 0;
+	eth_dev->data->all_multicast = 0;
+
+	memset(dev_private, 0, sizeof(*dev_private));
+	eth_dev->data->dev_private = dev_private;
+
+	eth_dev->dev_ops = dev_ops;
+
+	/* Copy default device operation functions */
+	memcpy(eth_dev->dev_ops, &virtual_ethdev_default_dev_ops,
+			sizeof(*eth_dev->dev_ops));
+
+	eth_dev->pci_dev = pci_dev;
+	eth_dev->pci_dev->driver = &eth_drv->pci_drv;
+
+	eth_dev->pci_dev->driver->id_table->device_id = 0xBEEF;
+
+	eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_success;
+	eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_success;
+
+	return eth_dev->data->port_id;
+
+err:
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (pci_drv)
+		rte_free(pci_drv);
+	if (eth_drv)
+		rte_free(eth_drv);
+	if (dev_ops)
+		rte_free(dev_ops);
+	if (id_table)
+		rte_free(id_table);
+	if (dev_private)
+		rte_free(dev_private);
+
+	return -1;
+}
diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h
new file mode 100644
index 0000000..766b6ac
--- /dev/null
+++ b/app/test/virtual_pmd.h
@@ -0,0 +1,74 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VIRTUAL_ETHDEV_H_
+#define __VIRTUAL_ETHDEV_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ether.h>
+
+int virtual_ethdev_init(void);
+
+int virtual_ethdev_create(const char *name, struct ether_addr *mac_addr, uint8_t socket_id);
+
+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);
+
+void virtual_ethdev_stop_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_rx_queue_setup_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_link_update_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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VIRTUAL_ETHDEV_H_ */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v2 3/4] Adding link bonding support to testpmd. - Includes the ability to create new bonded devices. - Add /remove bonding slave devices. - Interogate bonded device stats/configuration - Change bonding modes and select balance transmit polices
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
                     ` (2 preceding siblings ...)
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 0/4] Link Bonding Library declan.doherty
@ 2014-06-04 15:18   ` declan.doherty
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 4/4] Add Link Bonding Library to Doxygen declan.doherty
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 127+ messages in thread
From: declan.doherty @ 2014-06-04 15:18 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

- Display of port mac address fix
- Checkpatch fixes

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 app/test-pmd/cmdline.c    | 570 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/config.c     |   4 +-
 app/test-pmd/parameters.c |   4 +-
 app/test-pmd/testpmd.c    |  37 ++-
 app/test-pmd/testpmd.h    |   2 +
 5 files changed, 610 insertions(+), 7 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 0be28f6..27909f3 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -84,6 +84,9 @@
 #include <cmdline_socket.h>
 #include <cmdline.h>
 #include <rte_pci_dev_ids.h>
+#ifdef RTE_LIBRTE_BOND
+#include <rte_bond.h>
+#endif
 
 #include "testpmd.h"
 
@@ -393,6 +396,31 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"   Show the bypass configuration for a bypass enabled NIC"
 			" using the lowest port on the NIC.\n\n"
 #endif
+#ifdef RTE_LIBRTE_BOND
+			"create bonded device (mode) (socket)\n"
+			"	Create a new bonded device with specific bonding mode and socket.\n\n"
+
+			"add bonding slave (slave_id) (port_id)\n"
+			"	Add a slave device to a bonded device.\n\n"
+
+			"remove bonding slave (slave_id) (port_id)\n"
+			"	Remove a slave device from a bonded device.\n\n"
+
+			"set bonding mode (value) (port_id)\n"
+			"	Set the bonding mode on a bonded device.\n\n"
+
+			"set bonding primary (slave_id) (port_id)\n"
+			"	Set the primary slave for a bonded device.\n\n"
+
+			"show bonding config (port_id)\n"
+			"	Show the bonding config for port_id.\n\n"
+
+			"set bonding mac_addr (port_id) (address)\n"
+			"	Set the MAC address of a bonded device.\n\n"
+
+			"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"
+#endif
 
 			, list_pkt_forwarding_modes()
 		);
@@ -2849,6 +2877,538 @@ cmdline_parse_inst_t cmd_show_bypass_config = {
 };
 #endif
 
+#ifdef RTE_LIBRTE_BOND
+/* *** SET BONDING MODE *** */
+struct cmd_set_bonding_mode_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t mode;
+	uint8_t value;
+	uint8_t port_id;
+};
+
+static void cmd_set_bonding_mode_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_set_bonding_mode_result *res = parsed_result;
+	portid_t port_id = res->port_id;
+
+	/* Set the bonding mode for the relevant port. */
+	if (0 != rte_eth_bond_mode_set(port_id, res->value))
+		printf("\t Failed to set bonding mode for port = %d.\n", port_id);
+}
+
+cmdline_parse_token_string_t cmd_setbonding_mode_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_mode_result,
+		set, "set");
+cmdline_parse_token_string_t cmd_setbonding_mode_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_mode_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_mode_mode =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_mode_result,
+		mode, "mode");
+cmdline_parse_token_num_t cmd_setbonding_mode_value =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_mode_result,
+		value, UINT8);
+cmdline_parse_token_num_t cmd_setbonding_mode_port =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_mode_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_set_bonding_mode = {
+		.f = cmd_set_bonding_mode_parsed,
+		.help_str = "set bonding mode (mode_value) (port_id): Set the bonding mode for port_id",
+		.data = NULL,
+		.tokens = {
+				(void *) &cmd_setbonding_mode_set,
+				(void *) &cmd_setbonding_mode_bonding,
+				(void *) &cmd_setbonding_mode_mode,
+				(void *) &cmd_setbonding_mode_value,
+				(void *) &cmd_setbonding_mode_port,
+				NULL
+		}
+};
+
+/* *** SET BALANCE XMIT POLICY *** */
+struct cmd_set_bonding_balance_xmit_policy_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t balance_xmit_policy;
+	uint8_t port_id;
+	cmdline_fixed_string_t policy;
+};
+
+static void cmd_set_bonding_balance_xmit_policy_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_set_bonding_balance_xmit_policy_result *res = parsed_result;
+	portid_t port_id = res->port_id;
+	uint8_t policy;
+
+	if (!strcmp(res->policy, "l2")) {
+		policy = BALANCE_XMIT_POLICY_LAYER2;
+	} else if (!strcmp(res->policy, "l23")) {
+		policy = BALANCE_XMIT_POLICY_LAYER23;
+	} else if (!strcmp(res->policy, "l34")) {
+		policy = BALANCE_XMIT_POLICY_LAYER34;
+	} else {
+		printf("\t Invalid xmit policy selection");
+		return;
+	}
+
+	/* Set the bonding mode for the relevant port. */
+	if (0 != rte_eth_bond_xmit_policy_set(port_id, policy)) {
+		printf("\t Failed to set bonding balance xmit policy for port = %d.\n",
+				port_id);
+	}
+}
+
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		set, "set");
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_balance_xmit_policy =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		balance_xmit_policy, "balance_xmit_policy");
+cmdline_parse_token_num_t cmd_setbonding_balance_xmit_policy_port =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_policy =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+		policy, "l2#l23#l34");
+
+cmdline_parse_inst_t cmd_set_balance_xmit_policy = {
+		.f = cmd_set_bonding_balance_xmit_policy_parsed,
+		.help_str = "set bonding balance_xmit_policy (port_id) (policy_value): Set the bonding balance_xmit_policy for port_id",
+		.data = NULL,
+		.tokens = {
+				(void *)&cmd_setbonding_balance_xmit_policy_set,
+				(void *)&cmd_setbonding_balance_xmit_policy_bonding,
+				(void *)&cmd_setbonding_balance_xmit_policy_balance_xmit_policy,
+				(void *)&cmd_setbonding_balance_xmit_policy_port,
+				(void *)&cmd_setbonding_balance_xmit_policy_policy,
+				NULL
+		}
+};
+
+/* *** SHOW NIC BONDING CONFIGURATION *** */
+struct cmd_show_bonding_config_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t config;
+	uint8_t port_id;
+};
+
+static void cmd_show_bonding_config_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_show_bonding_config_result *res = parsed_result;
+	int bonding_mode;
+	const uint8_t *slaves;
+	int num_slaves, num_active_slaves;
+	int primary_id;
+	int i;
+	portid_t port_id = res->port_id;
+
+	/* Display the bonding mode.*/
+	bonding_mode = rte_eth_bond_mode_get(port_id);
+	if (bonding_mode < 0) {
+		printf("\tFailed to get bonding mode for port = %d\n", port_id);
+		return;
+	} else
+		printf("\tBonding mode: %d\n", bonding_mode);
+
+	if (bonding_mode == BONDING_MODE_BALANCE) {
+		int balance_xmit_policy;
+
+		balance_xmit_policy = rte_eth_bond_xmit_policy_get(port_id);
+		if (balance_xmit_policy < 0) {
+			printf("\tFailed to get balance xmit policy for port = %d\n",
+					port_id);
+			return;
+		} else {
+			printf("\tBalance Xmit Policy: ");
+
+			switch (balance_xmit_policy) {
+			case BALANCE_XMIT_POLICY_LAYER2:
+				printf("BALANCE_XMIT_POLICY_LAYER2");
+				break;
+			case BALANCE_XMIT_POLICY_LAYER23:
+				printf("BALANCE_XMIT_POLICY_LAYER23");
+				break;
+			case BALANCE_XMIT_POLICY_LAYER34:
+				printf("BALANCE_XMIT_POLICY_LAYER34");
+				break;
+			}
+			printf("\n");
+		}
+	}
+
+	num_slaves = rte_eth_bond_slaves_get(port_id, &slaves);
+
+	if (num_slaves < 0) {
+		printf("\tFailed to get slave list for port = %d\n", port_id);
+		return;
+	}
+	if (num_slaves > 0) {
+		printf("\tSlaves (%d): [", num_slaves);
+		for (i = 0; i < num_slaves - 1; i++)
+			printf("%d ", slaves[i]);
+
+		printf("%d]\n", slaves[num_slaves - 1]);
+	} else {
+		printf("\tSlaves: []\n");
+
+	}
+
+	num_active_slaves = rte_eth_bond_active_slaves_get(port_id, &slaves);
+
+	if (num_active_slaves < 0) {
+		printf("\tFailed to get active slave list for port = %d\n", port_id);
+		return;
+	}
+	if (num_active_slaves > 0) {
+		printf("\tActive Slaves (%d): [", num_active_slaves);
+		for (i = 0; i < num_active_slaves - 1; i++)
+			printf("%d ", slaves[i]);
+
+		printf("%d]\n", slaves[num_active_slaves - 1]);
+
+	} else {
+		printf("\tActive Slaves: []\n");
+
+	}
+
+	primary_id = rte_eth_bond_primary_get(port_id);
+	if (primary_id < 0) {
+		printf("\tFailed to get primary slave for port = %d\n", port_id);
+		return;
+	} else
+		printf("\tPrimary: [%d]\n", primary_id);
+
+}
+
+cmdline_parse_token_string_t cmd_showbonding_config_show =
+TOKEN_STRING_INITIALIZER(struct cmd_show_bonding_config_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_showbonding_config_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_show_bonding_config_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_showbonding_config_config =
+TOKEN_STRING_INITIALIZER(struct cmd_show_bonding_config_result,
+		config, "config");
+cmdline_parse_token_num_t cmd_showbonding_config_port =
+TOKEN_NUM_INITIALIZER(struct cmd_show_bonding_config_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_show_bonding_config = {
+		.f = cmd_show_bonding_config_parsed,
+		.help_str =	"show bonding config (port_id): Show the bonding config for port_id",
+		.data = NULL,
+		.tokens = {
+				(void *)&cmd_showbonding_config_show,
+				(void *)&cmd_showbonding_config_bonding,
+				(void *)&cmd_showbonding_config_config,
+				(void *)&cmd_showbonding_config_port,
+				NULL
+		}
+};
+
+/* *** SET BONDING PRIMARY *** */
+struct cmd_set_bonding_primary_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t primary;
+	uint8_t slave_id;
+	uint8_t port_id;
+};
+
+static void cmd_set_bonding_primary_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_set_bonding_primary_result *res = parsed_result;
+	portid_t master_port_id = res->port_id;
+	portid_t slave_port_id = res->slave_id;
+
+	/* Set the primary slave for a bonded device. */
+	if (0 != rte_eth_bond_primary_set(master_port_id, slave_port_id)) {
+		printf("\t Failed to set primary slave for port = %d.\n",
+				master_port_id);
+		return;
+	}
+	init_port_config();
+}
+
+cmdline_parse_token_string_t cmd_setbonding_primary_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_primary_result,
+		set, "set");
+cmdline_parse_token_string_t cmd_setbonding_primary_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_primary_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_primary_primary =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_primary_result,
+		primary, "primary");
+cmdline_parse_token_num_t cmd_setbonding_primary_slave =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_primary_result,
+		slave_id, UINT8);
+cmdline_parse_token_num_t cmd_setbonding_primary_port =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_primary_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_set_bonding_primary = {
+		.f = cmd_set_bonding_primary_parsed,
+		.help_str = "set bonding primary (slave_id) (port_id): Set the primary slave for port_id",
+		.data = NULL,
+		.tokens = {
+				(void *)&cmd_setbonding_primary_set,
+				(void *)&cmd_setbonding_primary_bonding,
+				(void *)&cmd_setbonding_primary_primary,
+				(void *)&cmd_setbonding_primary_slave,
+				(void *)&cmd_setbonding_primary_port,
+				NULL
+		}
+};
+
+/* *** ADD SLAVE *** */
+struct cmd_add_bonding_slave_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t slave;
+	uint8_t slave_id;
+	uint8_t port_id;
+};
+
+static void cmd_add_bonding_slave_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_add_bonding_slave_result *res = parsed_result;
+	portid_t master_port_id = res->port_id;
+	portid_t slave_port_id = res->slave_id;
+
+	/* Set the primary slave for a bonded device. */
+	if (0 != rte_eth_bond_slave_add(master_port_id, slave_port_id)) {
+		printf("\t Failed to add slave %d to master port = %d.\n",
+				slave_port_id, master_port_id);
+		return;
+	}
+	init_port_config();
+}
+
+cmdline_parse_token_string_t cmd_addbonding_slave_add =
+TOKEN_STRING_INITIALIZER(struct cmd_add_bonding_slave_result,
+		add, "add");
+cmdline_parse_token_string_t cmd_addbonding_slave_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_add_bonding_slave_result,
+		bonding, "bonding");
+cmdline_parse_token_string_t cmd_addbonding_slave_slave =
+TOKEN_STRING_INITIALIZER(struct cmd_add_bonding_slave_result,
+		slave, "slave");
+cmdline_parse_token_num_t cmd_addbonding_slave_slaveid =
+TOKEN_NUM_INITIALIZER(struct cmd_add_bonding_slave_result,
+		slave_id, UINT8);
+cmdline_parse_token_num_t cmd_addbonding_slave_port =
+TOKEN_NUM_INITIALIZER(struct cmd_add_bonding_slave_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_add_bonding_slave = {
+		.f = cmd_add_bonding_slave_parsed,
+		.help_str = "add bonding slave (slave_id) (port_id): Add a slave device to a bonded device",
+		.data = NULL,
+		.tokens = {
+				(void *)&cmd_addbonding_slave_add,
+				(void *)&cmd_addbonding_slave_bonding,
+				(void *)&cmd_addbonding_slave_slave,
+				(void *)&cmd_addbonding_slave_slaveid,
+				(void *)&cmd_addbonding_slave_port,
+				NULL
+		}
+};
+
+/* *** REMOVE SLAVE *** */
+struct cmd_remove_bonding_slave_result {
+	cmdline_fixed_string_t remove;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t slave;
+	uint8_t slave_id;
+	uint8_t port_id;
+};
+
+static void cmd_remove_bonding_slave_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_remove_bonding_slave_result *res = parsed_result;
+	portid_t master_port_id = res->port_id;
+	portid_t slave_port_id = res->slave_id;
+
+	/* Set the primary slave for a bonded device. */
+	if (0 != rte_eth_bond_slave_remove(master_port_id, slave_port_id)) {
+		printf("\t Failed to remove slave %d from master port = %d.\n",
+				slave_port_id, master_port_id);
+		return;
+	}
+	init_port_config();
+}
+
+cmdline_parse_token_string_t cmd_removebonding_slave_remove =
+		TOKEN_STRING_INITIALIZER(struct cmd_remove_bonding_slave_result,
+				remove, "remove");
+cmdline_parse_token_string_t cmd_removebonding_slave_bonding =
+		TOKEN_STRING_INITIALIZER(struct cmd_remove_bonding_slave_result,
+				bonding, "bonding");
+cmdline_parse_token_string_t cmd_removebonding_slave_slave =
+		TOKEN_STRING_INITIALIZER(struct cmd_remove_bonding_slave_result,
+				slave, "slave");
+cmdline_parse_token_num_t cmd_removebonding_slave_slaveid =
+		TOKEN_NUM_INITIALIZER(struct cmd_remove_bonding_slave_result,
+				slave_id, UINT8);
+cmdline_parse_token_num_t cmd_removebonding_slave_port =
+		TOKEN_NUM_INITIALIZER(struct cmd_remove_bonding_slave_result,
+				port_id, UINT8);
+
+cmdline_parse_inst_t cmd_remove_bonding_slave = {
+		.f = cmd_remove_bonding_slave_parsed,
+		.help_str = "remove bonding slave (slave_id) (port_id): Remove a slave device from a bonded device",
+		.data = NULL,
+		.tokens = {
+				(void *)&cmd_removebonding_slave_remove,
+				(void *)&cmd_removebonding_slave_bonding,
+				(void *)&cmd_removebonding_slave_slave,
+				(void *)&cmd_removebonding_slave_slaveid,
+				(void *)&cmd_removebonding_slave_port,
+				NULL
+		}
+};
+
+/* *** CREATE BONDED DEVICE *** */
+struct cmd_create_bonded_device_result {
+	cmdline_fixed_string_t create;
+	cmdline_fixed_string_t bonded;
+	cmdline_fixed_string_t device;
+	uint8_t mode;
+	uint8_t socket;
+};
+
+static void cmd_create_bonded_device_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_create_bonded_device_result *res = parsed_result;
+
+	int port_id;
+	if (test_done == 0) {
+		printf("Please stop forwarding first\n");
+		return;
+	}
+
+	port_id = rte_eth_bond_create("testpmd-bonded-dev", res->mode, res->socket);
+	/* Create a new bonded device. */
+	if (port_id < 0) {
+		printf("\t Failed to create bonded device.\n");
+		return;
+	} else {
+		printf("\t Created new bonded device (port %d).\n", port_id);
+		/* Update number of ports */
+		nb_ports = rte_eth_dev_count();
+		reconfig(port_id);
+		rte_eth_promiscuous_enable(port_id);
+	}
+
+}
+
+cmdline_parse_token_string_t cmd_createbonded_device_create =
+		TOKEN_STRING_INITIALIZER(struct cmd_create_bonded_device_result,
+				create, "create");
+cmdline_parse_token_string_t cmd_createbonded_device_bonded =
+		TOKEN_STRING_INITIALIZER(struct cmd_create_bonded_device_result,
+				bonded, "bonded");
+cmdline_parse_token_string_t cmd_createbonded_device_device =
+		TOKEN_STRING_INITIALIZER(struct cmd_create_bonded_device_result,
+				device, "device");
+cmdline_parse_token_num_t cmd_createbonded_device_mode =
+		TOKEN_NUM_INITIALIZER(struct cmd_create_bonded_device_result,
+				mode, UINT8);
+cmdline_parse_token_num_t cmd_createbonded_device_socket =
+		TOKEN_NUM_INITIALIZER(struct cmd_create_bonded_device_result,
+				socket, UINT8);
+
+cmdline_parse_inst_t cmd_create_bonded_device = {
+		.f = cmd_create_bonded_device_parsed,
+		.help_str = "create bonded device (mode) (socket): Create a new bonded device with specific bonding mode and socket",
+		.data = NULL,
+		.tokens = {
+				(void *)&cmd_createbonded_device_create,
+				(void *)&cmd_createbonded_device_bonded,
+				(void *)&cmd_createbonded_device_device,
+				(void *)&cmd_createbonded_device_mode,
+				(void *)&cmd_createbonded_device_socket,
+				NULL
+		}
+};
+
+/* *** SET MAC ADDRESS IN BONDED DEVICE *** */
+struct cmd_set_bond_mac_addr_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t bonding;
+	cmdline_fixed_string_t mac_addr;
+	uint8_t port_num;
+	struct ether_addr address;
+};
+
+static void cmd_set_bond_mac_addr_parsed(void *parsed_result,
+		__attribute__((unused))  struct cmdline *cl,
+		__attribute__((unused)) void *data)
+{
+	struct cmd_set_bond_mac_addr_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_mac_address_set(res->port_num, &res->address);
+
+	/* 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_mac_addr_set =
+		TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mac_addr_result, set, "set");
+cmdline_parse_token_string_t cmd_set_bond_mac_addr_bonding =
+		TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mac_addr_result, bonding,
+				"bonding");
+cmdline_parse_token_string_t cmd_set_bond_mac_addr_mac =
+		TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mac_addr_result, mac_addr,
+				"mac_addr");
+cmdline_parse_token_num_t cmd_set_bond_mac_addr_portnum =
+		TOKEN_NUM_INITIALIZER(struct cmd_set_bond_mac_addr_result, port_num, UINT8);
+cmdline_parse_token_etheraddr_t cmd_set_bond_mac_addr_addr =
+		TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_bond_mac_addr_result, address);
+
+cmdline_parse_inst_t cmd_set_bond_mac_addr = {
+		.f = cmd_set_bond_mac_addr_parsed,
+		.data = (void *) 0,
+		.help_str = "set bonding mac_addr (port_id) (address): ",
+		.tokens = {
+				(void *)&cmd_set_bond_mac_addr_set,
+				(void *)&cmd_set_bond_mac_addr_bonding,
+				(void *)&cmd_set_bond_mac_addr_mac,
+				(void *)&cmd_set_bond_mac_addr_portnum,
+				(void *)&cmd_set_bond_mac_addr_addr,
+				NULL
+		}
+};
+
+#endif /* RTE_LIBRTE_BOND */
+
 /* *** SET FORWARDING MODE *** */
 struct cmd_set_fwd_mode_result {
 	cmdline_fixed_string_t set;
@@ -5333,6 +5893,16 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_set_bypass_timeout,
 	(cmdline_parse_inst_t *)&cmd_show_bypass_config,
 #endif
+#ifdef RTE_LIBRTE_BOND
+	(cmdline_parse_inst_t *) &cmd_set_bonding_mode,
+	(cmdline_parse_inst_t *) &cmd_show_bonding_config,
+	(cmdline_parse_inst_t *) &cmd_set_bonding_primary,
+	(cmdline_parse_inst_t *) &cmd_add_bonding_slave,
+	(cmdline_parse_inst_t *) &cmd_remove_bonding_slave,
+	(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,
+#endif
 	(cmdline_parse_inst_t *)&cmd_vlan_offload,
 	(cmdline_parse_inst_t *)&cmd_vlan_tpid,
 	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter_all,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index d6291e7..1ef9a39 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -242,6 +242,7 @@ void
 port_infos_display(portid_t port_id)
 {
 	struct rte_port *port;
+	struct ether_addr mac_addr;
 	struct rte_eth_link link;
 	int vlan_offload;
 	struct rte_mempool * mp;
@@ -255,7 +256,8 @@ port_infos_display(portid_t port_id)
 	rte_eth_link_get_nowait(port_id, &link);
 	printf("\n%s Infos for port %-2d %s\n",
 	       info_border, port_id, info_border);
-	print_ethaddr("MAC address: ", &port->eth_addr);
+	rte_eth_macaddr_get(port_id, &mac_addr);
+	print_ethaddr("MAC address: ", &mac_addr);
 	printf("\nConnect to socket: %u", port->socket_id);
 
 	if (port_numa[port_id] != NUMA_NO_CONFIG) {
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 7a60048..6b44ef0 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -75,7 +75,9 @@
 #include <cmdline_parse.h>
 #include <cmdline_parse_etheraddr.h>
 #endif
-
+#ifdef RTE_LIBRTE_BOND
+#include <rte_bond.h>
+#endif
 #include "testpmd.h"
 
 static void
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index bc38305..823c973 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -300,7 +300,7 @@ struct rte_fdir_conf fdir_conf = {
 	.drop_queue = 127,
 };
 
-static volatile int test_done = 1; /* stop packet forwarding when set to 1. */
+volatile int test_done = 1; /* stop packet forwarding when set to 1. */
 
 struct queue_stats_mappings tx_queue_stats_mappings_array[MAX_TX_QUEUE_STATS_MAPPINGS];
 struct queue_stats_mappings rx_queue_stats_mappings_array[MAX_RX_QUEUE_STATS_MAPPINGS];
@@ -625,6 +625,32 @@ init_config(void)
 		rte_exit(EXIT_FAILURE, "FAIL from init_fwd_streams()\n");
 }
 
+
+void
+reconfig(portid_t new_port_id)
+{
+	struct rte_port *port;
+
+	/* Reconfiguration of Ethernet ports. */
+	ports = rte_realloc(ports,
+			    sizeof(struct rte_port) * nb_ports,
+			    CACHE_LINE_SIZE);
+	if (ports == NULL) {
+		rte_exit(EXIT_FAILURE, "rte_realloc(%d struct rte_port) failed\n",
+				nb_ports);
+	}
+
+	port = &ports[new_port_id];
+	rte_eth_dev_info_get(new_port_id, &port->dev_info);
+
+	/* set flag to initialize port/queue */
+	port->need_reconfig = 1;
+	port->need_reconfig_queues = 1;
+
+	init_port_config();
+}
+
+
 int
 init_fwd_streams(void)
 {
@@ -1232,7 +1258,7 @@ start_port(portid_t pid)
 	portid_t pi;
 	queueid_t qi;
 	struct rte_port *port;
-	uint8_t *mac_addr;
+	struct ether_addr mac_addr;
 
 	if (test_done == 0) {
 		printf("Please stop forwarding first\n");
@@ -1360,10 +1386,11 @@ start_port(portid_t pid)
 			RTE_PORT_HANDLING, RTE_PORT_STARTED) == 0)
 			printf("Port %d can not be set into started\n", pi);
 
-		mac_addr = port->eth_addr.addr_bytes;
+		rte_eth_macaddr_get(pi, &mac_addr);
 		printf("Port %d: %02X:%02X:%02X:%02X:%02X:%02X\n", pi,
-		       mac_addr[0], mac_addr[1], mac_addr[2],
-		       mac_addr[3], mac_addr[4], mac_addr[5]);
+				mac_addr.addr_bytes[0], mac_addr.addr_bytes[1],
+				mac_addr.addr_bytes[2], mac_addr.addr_bytes[3],
+				mac_addr.addr_bytes[4], mac_addr.addr_bytes[5]);
 
 		/* at least one port started, need checking link status */
 		need_check_link_status = 1;
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 0cf5a92..1f54787 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -279,6 +279,7 @@ extern uint16_t port_topology; /**< set by "--port-topology" parameter */
 extern uint8_t no_flush_rx; /**<set by "--no-flush-rx" parameter */
 extern uint8_t  mp_anon; /**< set by "--mp-anon" parameter */
 extern uint8_t no_link_check; /**<set by "--disable-link-check" parameter */
+extern volatile int test_done; /* stop packet forwarding when set to 1. */
 
 #ifdef RTE_NIC_BYPASS
 extern uint32_t bypass_timeout; /**< Store the NIC bypass watchdog timeout */
@@ -452,6 +453,7 @@ void fwd_config_display(void);
 void rxtx_config_display(void);
 void fwd_config_setup(void);
 void set_def_fwd_config(void);
+void reconfig(portid_t new_port_id);
 int init_fwd_streams(void);
 
 
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v2 4/4] Add Link Bonding Library to Doxygen
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
                     ` (3 preceding siblings ...)
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 3/4] Adding link bonding support to testpmd. - Includes the ability to create new bonded devices. - Add /remove bonding slave devices. - Interogate bonded device stats/configuration - Change bonding modes and select balance transmit polices declan.doherty
@ 2014-06-04 15:18   ` declan.doherty
  2014-06-04 16:10   ` [dpdk-dev] [PATCH v2 0/4] Link Bonding Library Doherty, Declan
                     ` (4 subsequent siblings)
  9 siblings, 0 replies; 127+ messages in thread
From: declan.doherty @ 2014-06-04 15:18 UTC (permalink / raw)
  To: dev, dev

From: Declan Doherty <declan.doherty@intel.com>

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 doc/doxy-api-index.md | 1 +
 doc/doxy-api.conf     | 1 +
 2 files changed, 2 insertions(+)

diff --git a/doc/doxy-api-index.md b/doc/doxy-api-index.md
index 2825c08..2206c68 100644
--- a/doc/doxy-api-index.md
+++ b/doc/doxy-api-index.md
@@ -36,6 +36,7 @@ API {#index}
 There are many libraries, so their headers may be grouped by topics:
 
 - **device**:
+  [bond]               (@ref rte_bond.h),
   [ethdev]             (@ref rte_ethdev.h),
   [devargs]            (@ref rte_devargs.h),
   [KNI]                (@ref rte_kni.h),
diff --git a/doc/doxy-api.conf b/doc/doxy-api.conf
index 642f77a..a9c5b30 100644
--- a/doc/doxy-api.conf
+++ b/doc/doxy-api.conf
@@ -30,6 +30,7 @@
 
 PROJECT_NAME            = DPDK
 INPUT                   = doc/doxy-api-index.md \
+                          lib/librte_bond \
                           lib/librte_eal/common/include \
                           lib/librte_ether \
                           lib/librte_hash \
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
                     ` (4 preceding siblings ...)
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 4/4] Add Link Bonding Library to Doxygen declan.doherty
@ 2014-06-04 16:10   ` Doherty, Declan
  2014-06-05  8:03   ` De Lara Guarch, Pablo
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 127+ messages in thread
From: Doherty, Declan @ 2014-06-04 16:10 UTC (permalink / raw)
  To: dev

Sorry for the double submission of the first 3 parts of this patch set. It was meant to be a test directed to my own email account.
Regards
Declan

> -----Original Message-----
> From: Doherty, Declan
> Sent: Wednesday, June 4, 2014 4:19 PM
> To: dev@dpdk.org; dev@dpdk.org
> Cc: Doherty, Declan
> Subject: [PATCH v2 0/4] Link Bonding Library
> 
> From: Declan Doherty <declan.doherty@intel.com>
> 
> v2 patch additions,
> fix for tx burst broadcast, incrementing the reference count on each mbuf by
> the number of slaves - 1
> add/remove slave behavior chnange to fix primary slave port assignment
> patchcheck code fixes
> 
> Initial release of Link Bonding Library (lib/librte_bond) with support for
> bonding modes :
>  0 - Round Robin
>  1 - Active Backup
>  2 - Balance l2 / l23 / l34
>  3 - Broadcast
> 
> patches split:
>  1 - library + makefile changes
>  2 - Unit test suite, including code to generate packet bursts for
>     testing rx and tx functionality of bonded device and a
>     virtual/stubbed out ethdev for use as slave ethdev in testing
>  3 - Link bonding integration into testpmd, including :
>      - Includes the ability to  create new bonded devices.
>      - Add /remove bonding slave devices.
>      - Interogate bonded device stats/configuration
>      - Change bonding modes and select balance transmit polices
>  4 - Add Link Bonding Library to Doxygen
> 
> 
>  app/test-pmd/cmdline.c            |  570 ++++++
>  app/test-pmd/config.c             |    4 +-
>  app/test-pmd/parameters.c         |    4 +-
>  app/test-pmd/testpmd.c            |   37 +-
>  app/test-pmd/testpmd.h            |    2 +
>  app/test/Makefile                 |    3 +
>  app/test/commands.c               |    3 +
>  app/test/packet_burst_generator.c |  289 +++
>  app/test/packet_burst_generator.h |   78 +
>  app/test/test.h                   |    1 +
>  app/test/test_link_bonding.c      | 3943
> +++++++++++++++++++++++++++++++++++++
>  app/test/virtual_pmd.c            |  574 ++++++
>  app/test/virtual_pmd.h            |   74 +
>  config/common_bsdapp              |    5 +
>  config/common_linuxapp            |    5 +
>  doc/doxy-api-index.md             |    1 +
>  doc/doxy-api.conf                 |    1 +
>  lib/Makefile                      |    1 +
>  lib/librte_bond/Makefile          |   28 +
>  lib/librte_bond/rte_bond.c        | 1682 ++++++++++++++++
>  lib/librte_bond/rte_bond.h        |  228 +++
>  mk/rte.app.mk                     |    5 +
>  22 files changed, 7531 insertions(+), 7 deletions(-)
>  create mode 100644 app/test/packet_burst_generator.c
>  create mode 100644 app/test/packet_burst_generator.h
>  create mode 100644 app/test/test_link_bonding.c
>  create mode 100644 app/test/virtual_pmd.c
>  create mode 100644 app/test/virtual_pmd.h
>  create mode 100644 lib/librte_bond/Makefile
>  create mode 100644 lib/librte_bond/rte_bond.c
>  create mode 100644 lib/librte_bond/rte_bond.h
> 
> --
> 1.8.5.3

--------------------------------------------------------------
Intel Shannon Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263
Business address: Dromore House, East Park, Shannon, Co. Clare

This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
                     ` (5 preceding siblings ...)
  2014-06-04 16:10   ` [dpdk-dev] [PATCH v2 0/4] Link Bonding Library Doherty, Declan
@ 2014-06-05  8:03   ` De Lara Guarch, Pablo
  2014-06-05 11:03   ` Neil Horman
                     ` (2 subsequent siblings)
  9 siblings, 0 replies; 127+ messages in thread
From: De Lara Guarch, Pablo @ 2014-06-05  8:03 UTC (permalink / raw)
  To: Doherty, Declan, dev

Acked-by: Pablo de Lara Guarch <pablo.de.lara.guarch@intel.com>

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of
> declan.doherty@intel.com
> Sent: Wednesday, June 04, 2014 4:18 PM
> To: dev@dpdk.org; dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
> 
> From: Declan Doherty <declan.doherty@intel.com>
> 
> v2 patch additions,
> fix for tx burst broadcast, incrementing the reference count on each mbuf by
> the number of slaves - 1 add/remove slave behavior chnange to fix primary
> slave port assignment patchcheck code fixes
> 
> Initial release of Link Bonding Library (lib/librte_bond) with support for
> bonding modes :
>  0 - Round Robin
>  1 - Active Backup
>  2 - Balance l2 / l23 / l34
>  3 - Broadcast
> 
> patches split:
>  1 - library + makefile changes
>  2 - Unit test suite, including code to generate packet bursts for
>     testing rx and tx functionality of bonded device and a
>     virtual/stubbed out ethdev for use as slave ethdev in testing
>  3 - Link bonding integration into testpmd, including :
>      - Includes the ability to  create new bonded devices.
>      - Add /remove bonding slave devices.
>      - Interogate bonded device stats/configuration
>      - Change bonding modes and select balance transmit polices
>  4 - Add Link Bonding Library to Doxygen
> 
> 
>  app/test-pmd/cmdline.c            |  570 ++++++
>  app/test-pmd/config.c             |    4 +-
>  app/test-pmd/parameters.c         |    4 +-
>  app/test-pmd/testpmd.c            |   37 +-
>  app/test-pmd/testpmd.h            |    2 +
>  app/test/Makefile                 |    3 +
>  app/test/commands.c               |    3 +
>  app/test/packet_burst_generator.c |  289 +++
>  app/test/packet_burst_generator.h |   78 +
>  app/test/test.h                   |    1 +
>  app/test/test_link_bonding.c      | 3943
> +++++++++++++++++++++++++++++++++++++
>  app/test/virtual_pmd.c            |  574 ++++++
>  app/test/virtual_pmd.h            |   74 +
>  config/common_bsdapp              |    5 +
>  config/common_linuxapp            |    5 +
>  doc/doxy-api-index.md             |    1 +
>  doc/doxy-api.conf                 |    1 +
>  lib/Makefile                      |    1 +
>  lib/librte_bond/Makefile          |   28 +
>  lib/librte_bond/rte_bond.c        | 1682 ++++++++++++++++
>  lib/librte_bond/rte_bond.h        |  228 +++
>  mk/rte.app.mk                     |    5 +
>  22 files changed, 7531 insertions(+), 7 deletions(-)  create mode 100644
> app/test/packet_burst_generator.c  create mode 100644
> app/test/packet_burst_generator.h  create mode 100644
> app/test/test_link_bonding.c  create mode 100644 app/test/virtual_pmd.c
> create mode 100644 app/test/virtual_pmd.h  create mode 100644
> lib/librte_bond/Makefile  create mode 100644 lib/librte_bond/rte_bond.c
> create mode 100644 lib/librte_bond/rte_bond.h
> 
> --
> 1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
                     ` (6 preceding siblings ...)
  2014-06-05  8:03   ` De Lara Guarch, Pablo
@ 2014-06-05 11:03   ` Neil Horman
  2014-06-06  8:23     ` Doherty, Declan
  2014-06-06  3:26   ` Cao, Waterman
  2014-06-11 16:33   ` Thomas Monjalon
  9 siblings, 1 reply; 127+ messages in thread
From: Neil Horman @ 2014-06-05 11:03 UTC (permalink / raw)
  To: declan.doherty; +Cc: dev

On Wed, Jun 04, 2014 at 04:18:01PM +0100, declan.doherty@intel.com wrote:
> From: Declan Doherty <declan.doherty@intel.com>
> 
> v2 patch additions,
> fix for tx burst broadcast, incrementing the reference count on each mbuf by the number of slaves - 1 
> add/remove slave behavior chnange to fix primary slave port assignment 
> patchcheck code fixes 
> 
> Initial release of Link Bonding Library (lib/librte_bond) with support for bonding modes :
>  0 - Round Robin
>  1 - Active Backup
>  2 - Balance l2 / l23 / l34
>  3 - Broadcast
> 
> patches split:
>  1 - library + makefile changes
>  2 - Unit test suite, including code to generate packet bursts for
>     testing rx and tx functionality of bonded device and a
>     virtual/stubbed out ethdev for use as slave ethdev in testing
>  3 - Link bonding integration into testpmd, including :
>      - Includes the ability to  create new bonded devices.
>      - Add /remove bonding slave devices. 
>      - Interogate bonded device stats/configuration
>      - Change bonding modes and select balance transmit polices
>  4 - Add Link Bonding Library to Doxygen
> 
> 
>  app/test-pmd/cmdline.c            |  570 ++++++
>  app/test-pmd/config.c             |    4 +-
>  app/test-pmd/parameters.c         |    4 +-
>  app/test-pmd/testpmd.c            |   37 +-
>  app/test-pmd/testpmd.h            |    2 +
>  app/test/Makefile                 |    3 +
>  app/test/commands.c               |    3 +
>  app/test/packet_burst_generator.c |  289 +++
>  app/test/packet_burst_generator.h |   78 +
>  app/test/test.h                   |    1 +
>  app/test/test_link_bonding.c      | 3943 +++++++++++++++++++++++++++++++++++++
>  app/test/virtual_pmd.c            |  574 ++++++
>  app/test/virtual_pmd.h            |   74 +
>  config/common_bsdapp              |    5 +
>  config/common_linuxapp            |    5 +
>  doc/doxy-api-index.md             |    1 +
>  doc/doxy-api.conf                 |    1 +
>  lib/Makefile                      |    1 +
>  lib/librte_bond/Makefile          |   28 +
>  lib/librte_bond/rte_bond.c        | 1682 ++++++++++++++++
>  lib/librte_bond/rte_bond.h        |  228 +++
>  mk/rte.app.mk                     |    5 +
>  22 files changed, 7531 insertions(+), 7 deletions(-)
>  create mode 100644 app/test/packet_burst_generator.c
>  create mode 100644 app/test/packet_burst_generator.h
>  create mode 100644 app/test/test_link_bonding.c
>  create mode 100644 app/test/virtual_pmd.c
>  create mode 100644 app/test/virtual_pmd.h
>  create mode 100644 lib/librte_bond/Makefile
>  create mode 100644 lib/librte_bond/rte_bond.c
>  create mode 100644 lib/librte_bond/rte_bond.h
> 
> -- 
> 1.8.5.3
> 
> 
This doesn't address any of the comments I made previously.
Neil

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 1/4] " declan.doherty
  2014-06-04 15:18     ` declan.doherty
@ 2014-06-05 15:15     ` Stephen Hemminger
  2014-06-06  9:07       ` Doherty, Declan
  2014-06-09 21:11     ` Eric Kinzie
  2 siblings, 1 reply; 127+ messages in thread
From: Stephen Hemminger @ 2014-06-05 15:15 UTC (permalink / raw)
  To: declan.doherty; +Cc: dev

On Wed,  4 Jun 2014 16:18:02 +0100
declan.doherty@intel.com wrote:

> From: Declan Doherty <declan.doherty@intel.com>
> 
> - Broadcast TX burst broadcast bug fix
> - Add/remove slave behavior fix
> - Checkpatch fixes
> 
> Signed-off-by: Declan Doherty <declan.doherty@intel.com>

There are some pretty weak hash functions in there.

What about using:

--- a/lib/librte_eal/common/include/rte_common.h	2014-02-27 09:02:23.424698279 -0800
+++ b/lib/librte_eal/common/include/rte_common.h	2014-06-05 08:03:51.615839548 -0700
@@ -365,6 +365,31 @@ rte_str_to_size(const char *str)
 }
 
 /**
+ * Multiplicative hash functions useful to distrbute
+ * a uniform set of consective keys
+ *
+ * @param val
+ *	The input uniform key
+ * @param bits
+ *	Number of bits desired
+ */
+#define GOLDEN_RATIO_32      2654404609U
+static inline uint32_t
+rte_fib_hash32(uint32_t val, unsigned int bits)
+{
+	val *= GOLDEN_RATIO_32;
+	return val >> (32 - bits);
+}
+
+#define	GOLDEN_RATIO_64	0x9e37fffffffc0001UL
+static inline uint64_t
+rte_fib_hash64(uint64_t val, unsigned bits)
+{
+	val *= GOLDEN_RATIO_64;
+	return val >> (64 - bits);
+}
+
+/**
  * Function to terminate the application immediately, printing an error
  * message and returning the exit_code back to the shell.
  *
--- a/lib/librte_ether/rte_ether.h	2014-02-27 09:02:23.438697987 -0800
+++ b/lib/librte_ether/rte_ether.h	2014-06-05 08:14:15.438080058 -0700
@@ -48,6 +48,8 @@ extern "C" {
 
 #include <rte_memcpy.h>
 #include <rte_random.h>
+#include <rte_common.h>
+#include <rte_jhash.h>
 
 #define ETHER_ADDR_LEN  6 /**< Length of Ethernet address. */
 #define ETHER_TYPE_LEN  2 /**< Length of Ethernet type field. */
@@ -250,6 +252,80 @@ struct ether_hdr {
 	uint16_t ether_type;      /**< Frame type. */
 } __attribute__((__packed__));
 
+
+/*
+ * These functions work by aliasing the 6 byte Ethernet address
+ * into a 64 bit value. The macro shift16, removes the extra
+ * bytes with the correct shift depending on byte order
+ */
+#ifdef __BYTE_ORDER
+  #if __BYTE_ORDER == __BIG_ENDIAN
+    #define shift16(s) (s >>= 16)
+  #else
+    #define shift16(s) (s <<= 16)
+  #endif
+#endif
+
+/**
+ * Fast compare of  Ethernet address.
+ *
+ * @param e1
+ *   A pointer to a ether_addr structure one address
+ * @param e2
+ *   A pointer to a ether_addr structure holding other address
+ * @return
+ *   True  (1) if addresses are the same
+ *   false (0) otherwise.
+ */
+static inline int
+ether_addr_equal(const struct ether_addr *e1, const struct ether_addr *e2)
+{
+	uint64_t e1_addr = *(const uint64_t *) e1;
+	shift16(e1_addr);
+	uint64_t e2_addr = *(const uint64_t *) e2;
+	shift16(e2_addr);
+
+	return (e1_addr == e2_addr);
+}
+
+/**
+ * Fast hash of ethernet address
+ *
+ * @param ea
+ *   A pointer to a ether_addr structure
+ * @param bits
+ *   Number of bits desired
+ * @return
+ *   Calculated hash value.
+ */
+static inline uint32_t
+ether_addr_hash(const struct ether_addr *ea, unsigned bits)
+{
+	uint64_t val = *(const uint64_t *) ea;
+
+	shift16(val);
+	return rte_fib_hash64(val, bits);
+}
+#undef shift16
+
+/**
+ * Hash of ethernet source and destination
+ *
+ * @param ea
+ *   A pointer to a ether_hdr structure
+ * @param initval
+ *   Initialising value of hash.
+ * @return
+ *   Calculated hash value.
+ */
+static inline uint32_t
+ether_header_hash(const struct ether_hdr *hdr, unsigned seed)
+{
+	const uint32_t *key = (const uint32_t *)hdr;
+
+	return rte_jhash(key, 2*ETHER_ADDR_LEN, seed);
+}
+
 /**
  * Ethernet VLAN Header.
  * Contains the 16-bit VLAN Tag Control Identifier and the Ethernet type

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
                     ` (7 preceding siblings ...)
  2014-06-05 11:03   ` Neil Horman
@ 2014-06-06  3:26   ` Cao, Waterman
  2014-06-11 16:33   ` Thomas Monjalon
  9 siblings, 0 replies; 127+ messages in thread
From: Cao, Waterman @ 2014-06-06  3:26 UTC (permalink / raw)
  To: Doherty, Declan, dev

Tested-by: Waterman Cao <waterman.cao@intel.com>

This patch is updated version for Link Bonding library.
It's compose of 5 files including cover letter, tested by Intel.
Please see environment information:
Fedora 20 x86_64, Linux Kernel 3.11.10-301, GCC 4.8.2  
Intel Xeon CPU E5-2680 v2 @ 2.80GHz NIC: Intel Niantic 82599
Total cases        Passed               Failed   
       18            18                  0

Please see test Case list as the following:
Case1: Basic bonding--Create bonded devices and slaves 
Case2: Basic bonding--MAC Address Test 
Case3: Basic bonding--Device Promiscuous Mode Test
Case4: Mode 0(Round Robin) TX/RX test 
Case5: Mode 0(Round Robin) Bring one slave link down 
Case6: Mode 0(Round Robin) Bring all slave links down
Case7: Mode 1(Active Backup) TX/RX Test 
Case8: Mode 1(Active Backup) Change active slave, RX/TX test 
Case9: Mode 1(Active Backup) Link up/down active eth dev 
Case10: Mode 1(Active Backup) Bring all slave links down
Case11: Mode 2(Balance XOR) TX Load Balance test 
Case12: Mode 2(Balance XOR) TX Load Balance Link down 
Case13: Mode 2(Balance XOR) Bring all slave links down 
Case14: Mode 2(Balance XOR) Layer 3+4 forwarding 
Case15: Mode 2(Balance XOR) RX test
Case16: Mode 3(Broadcast) TX/RX Test 
Case17: Mode 3(Broadcast) Bring one slave link down 
Case18: Mode 3(Broadcast) Bring all slave links down

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-06-05 11:03   ` Neil Horman
@ 2014-06-06  8:23     ` Doherty, Declan
  2014-06-06 14:54       ` Neil Horman
  0 siblings, 1 reply; 127+ messages in thread
From: Doherty, Declan @ 2014-06-06  8:23 UTC (permalink / raw)
  To: dev

> -----Original Message-----
> From: Neil Horman [mailto:nhorman@tuxdriver.com]
> Sent: Thursday, May 29, 2014 12:34 PM
> To: Doherty, Declan
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
> 
> On Thu, May 29, 2014 at 10:33:00AM +0000, Doherty, Declan wrote:
> > -----Original Message-----
> > > From: Neil Horman [mailto:nhorman@tuxdriver.com]
> > > Sent: Wednesday, May 28, 2014 6:49 PM
> > > To: Doherty, Declan
> > > Cc: dev@dpdk.org
> > > Subject: Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
> > >
> > > On Wed, May 28, 2014 at 04:32:00PM +0100, declan.doherty@intel.com
> wrote:
> > > > From: Declan Doherty <declan.doherty@intel.com>
> > > >
> > > > Initial release of Link Bonding Library (lib/librte_bond) with 
> > > > support for bonding modes :
> > > >  0 - Round Robin
> > > >  1 - Active Backup
> > > >  2 - Balance l2 / l23 / l34
> > > >  3 - Broadcast
> > > >
> > > Why make this a separate library?  That requires exposure of yet 
> > > another
> API to applications.  Instead, why > not write a PMD that can enslave 
> other PMD's and treat them all as a single interface?  That way this 
> all >  > works with the existing API.
> > >
> > > Neil
> >
> > Hi Neil,
> > the link bonding device is essentially a software PMD, and as such 
> > supports
> all the standard PMD APIs, the only new APIs which the link bonding 
> library introduces  are for the control operations of the bonded 
> device which are currently unsupported by the standard PMD API.
> Operations such as creating, adding/removing slaves, and configuring 
> the modes of operation of the device have no analogous APIs in the 
> current PMD API and required new ones to be created .
> 
> Thats really only true in spirit, in the sense that this library 
> transmits and receives frames like a PMD does.  In practice it doesn't 
> work and isn't architected the same way.  You don't register the 
> driver using the same method as the other PMDs, which means that using 
> --vdev on the command line wont work for this type of device.  It also 
> implies that applications have to be made specifically aware of the 
> fact that they are using a bonded interface (i.e. they need to call 
> the bonding setup routines to create the bond).  I would
> recommend:
> 
> 1) Register the pmd using the PMD_DRIVER_REGISTER macro, like other 
> PMD's
> 2) Use the kvargs library to support configuration via the --vdev 
> command line option, so bonds can be created administratively, rather 
> than just programatically
> 3) Separate the command api from the PMD functionality into separate 
> libraries (use control mbufs to communicate configuration changes to 
> the pmd).  This will allow users to dynamically load the pmd 
> functionality (without compile or run time linking requirements), and 
> then optionally use the programatic interface (or not if they want to 
> save memory)
> 
> Regards
> Neil
> -----Original Message-----
> From: Neil Horman [mailto:nhorman@tuxdriver.com]
> Sent: Thursday, June 5, 2014 12:04 PM
> To: Doherty, Declan
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
> 
> On Wed, Jun 04, 2014 at 04:18:01PM +0100, declan.doherty@intel.com
> wrote:
> > From: Declan Doherty <declan.doherty@intel.com>
> >
> > v2 patch additions,
> > fix for tx burst broadcast, incrementing the reference count on each 
> > mbuf by the number of slaves - 1 add/remove slave behavior chnange 
> > to fix primary slave port assignment patchcheck code fixes
> >
> >
> >
> This doesn't address any of the comments I made previously.
> Neil


Hi Neil, 

sorry for not replying regarding this earlier, in relation to your recommendations 1 and 2, I'm currently working on the implementation of both and should have an additional patch within the next couple of days to add this functionality.

Regarding your third recommendation, I have no problem splitting the library into separate API and PMD libraries although this does seem to break convention with the other non hw based pmd's, such as pmd_pcap, so would prefer not to go down that route. Also, I don't see the ability to dynamically load the pmd as justification for the use of a control mbufs interface, this would require that either additional queues be created to handle control messages, or that the data TX queues have the ability to identify and process control mbufs, and either of these options will have a performance hit, for the core handling the separate control messages or directly to the tx burst performance. I am not currently aware of any functional requirements or use cases for bonded devices to be used over multiple processes which is the only reason I can see for using an interface based on control mbufs, and by providing a --vdev configuration options the user can still write their applications without any knowledge of the additional link bonding programmatic interface. If in the future a use case does emerge which requires multi-process control of bonded devices, I think it would make sense then to add an additional library to provide this functionality.

Regards
Declan
--------------------------------------------------------------
Intel Shannon Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263
Business address: Dromore House, East Park, Shannon, Co. Clare

This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
  2014-06-05 15:15     ` Stephen Hemminger
@ 2014-06-06  9:07       ` Doherty, Declan
  2014-06-06 15:13         ` Stephen Hemminger
  0 siblings, 1 reply; 127+ messages in thread
From: Doherty, Declan @ 2014-06-06  9:07 UTC (permalink / raw)
  To: dev

> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Thursday, June 5, 2014 4:16 PM
> To: Doherty, Declan
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
> 
> On Wed,  4 Jun 2014 16:18:02 +0100
> declan.doherty@intel.com wrote:
> 
> > From: Declan Doherty <declan.doherty@intel.com>
> >
> > - Broadcast TX burst broadcast bug fix
> > - Add/remove slave behavior fix
> > - Checkpatch fixes
> >
> > Signed-off-by: Declan Doherty <declan.doherty@intel.com>
> 
> There are some pretty weak hash functions in there.
> 
> What about using:
> .....

Hi Stephen,

I suppose the naming of these as hash functions is probably misleading, the aim is not to create a unique hash for each flow with minimal collisions but to  help balance traffic flows across the slaves of the bonded device, and as we are doing a modulus calculation based on the number of slaves attached, which I believe will typically be in the 2-4 range, I'm not sure that a stronger hashing function will give a better balance of flows across the slaves. For example in the Linux kernel implementation of the link bonding driver the mac hashing only uses the last byte of src & dst mac addresses to calculate it's eth hash.

/* L2 hash helper */
static inline u32 bond_eth_hash(struct sk_buff *skb)
{
	struct ethhdr *data = (struct ethhdr *)skb->data;

	if (skb_headlen(skb) >= offsetof(struct ethhdr, h_proto))
		return data->h_dest[5] ^ data->h_source[5];

	return 0;
}

I'll investigate and see if a stronger hashing function will result in a better balancing of flows.
--------------------------------------------------------------
Intel Shannon Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263
Business address: Dromore House, East Park, Shannon, Co. Clare

This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-06-06  8:23     ` Doherty, Declan
@ 2014-06-06 14:54       ` Neil Horman
  2014-06-13 14:56         ` Doherty, Declan
  0 siblings, 1 reply; 127+ messages in thread
From: Neil Horman @ 2014-06-06 14:54 UTC (permalink / raw)
  To: Doherty, Declan; +Cc: dev

On Fri, Jun 06, 2014 at 08:23:31AM +0000, Doherty, Declan wrote:
> > -----Original Message-----
> > From: Neil Horman [mailto:nhorman@tuxdriver.com]
> > Sent: Thursday, May 29, 2014 12:34 PM
> > To: Doherty, Declan
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
> > 
> > On Thu, May 29, 2014 at 10:33:00AM +0000, Doherty, Declan wrote:
> > > -----Original Message-----
> > > > From: Neil Horman [mailto:nhorman@tuxdriver.com]
> > > > Sent: Wednesday, May 28, 2014 6:49 PM
> > > > To: Doherty, Declan
> > > > Cc: dev@dpdk.org
> > > > Subject: Re: [dpdk-dev] [PATCH 0/4] Link Bonding Library
> > > >
> > > > On Wed, May 28, 2014 at 04:32:00PM +0100, declan.doherty@intel.com
> > wrote:
> > > > > From: Declan Doherty <declan.doherty@intel.com>
> > > > >
> > > > > Initial release of Link Bonding Library (lib/librte_bond) with 
> > > > > support for bonding modes :
> > > > >  0 - Round Robin
> > > > >  1 - Active Backup
> > > > >  2 - Balance l2 / l23 / l34
> > > > >  3 - Broadcast
> > > > >
> > > > Why make this a separate library?  That requires exposure of yet 
> > > > another
> > API to applications.  Instead, why > not write a PMD that can enslave 
> > other PMD's and treat them all as a single interface?  That way this 
> > all >  > works with the existing API.
> > > >
> > > > Neil
> > >
> > > Hi Neil,
> > > the link bonding device is essentially a software PMD, and as such 
> > > supports
> > all the standard PMD APIs, the only new APIs which the link bonding 
> > library introduces  are for the control operations of the bonded 
> > device which are currently unsupported by the standard PMD API.
> > Operations such as creating, adding/removing slaves, and configuring 
> > the modes of operation of the device have no analogous APIs in the 
> > current PMD API and required new ones to be created .
> > 
> > Thats really only true in spirit, in the sense that this library 
> > transmits and receives frames like a PMD does.  In practice it doesn't 
> > work and isn't architected the same way.  You don't register the 
> > driver using the same method as the other PMDs, which means that using 
> > --vdev on the command line wont work for this type of device.  It also 
> > implies that applications have to be made specifically aware of the 
> > fact that they are using a bonded interface (i.e. they need to call 
> > the bonding setup routines to create the bond).  I would
> > recommend:
> > 
> > 1) Register the pmd using the PMD_DRIVER_REGISTER macro, like other 
> > PMD's
> > 2) Use the kvargs library to support configuration via the --vdev 
> > command line option, so bonds can be created administratively, rather 
> > than just programatically
> > 3) Separate the command api from the PMD functionality into separate 
> > libraries (use control mbufs to communicate configuration changes to 
> > the pmd).  This will allow users to dynamically load the pmd 
> > functionality (without compile or run time linking requirements), and 
> > then optionally use the programatic interface (or not if they want to 
> > save memory)
> > 
> > Regards
> > Neil
> > -----Original Message-----
> > From: Neil Horman [mailto:nhorman@tuxdriver.com]
> > Sent: Thursday, June 5, 2014 12:04 PM
> > To: Doherty, Declan
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
> > 
> > On Wed, Jun 04, 2014 at 04:18:01PM +0100, declan.doherty@intel.com
> > wrote:
> > > From: Declan Doherty <declan.doherty@intel.com>
> > >
> > > v2 patch additions,
> > > fix for tx burst broadcast, incrementing the reference count on each 
> > > mbuf by the number of slaves - 1 add/remove slave behavior chnange 
> > > to fix primary slave port assignment patchcheck code fixes
> > >
> > >
> > >
> > This doesn't address any of the comments I made previously.
> > Neil
> 
> 
> Hi Neil, 
> 
> sorry for not replying regarding this earlier, in relation to your recommendations 1 and 2, I'm currently working on the implementation of both and should have an additional patch within the next couple of days to add this functionality.
> 
> Regarding your third recommendation, I have no problem splitting the library into separate API and PMD libraries although this does seem to break convention with the other non hw based pmd's, such as pmd_pcap,
I'm not at all sure what you mean here.  pmd_pcap registers a driver with the
registration mechanism, allowing for the use of the --vdev option on the command
line, same as all the other virtual drivers.  The physical drivers do the same
thing using the --whitelist and --blacklist options.  How is the bonding driver
following convention with pmd_pcap?


> so would prefer not to go down that route. Also, I don't see the ability to dynamically load the pmd as justification for the use of a control mbufs interface, this would require that either additional queues be created to handle control messages, or that the data TX queues have the ability to identify and process control mbufs, and either of these options will have a performance hit,

Well, you're correct in that the driver would have to identify control messages,
but I don't see how thats a performance hit at all.  If you create a control
channel queue, then all you have to introduce to the datapath is a single branch
to see which queue is transmitting, and your done. If control mbufs are just
that hurtful to performance, it seems thats an area that really needs
improvement then.  

Another alternative is to add a control packet method to the rte_eth_dev
structure allowing you to pass control mbufs directly to a pmd out of line with
the datapath.  That could avoid any additional branches in the datapath, and
still allow you to separate user api from driver implementation.


> for the core handling the separate control messages or directly to the tx burst performance. I am not currently aware of any functional requirements or use cases for bonded devices to be used over multiple processes which is the only reason I can see for using an interface based on control mbufs,

The reason is administrative.  Its got nothing to do with how many processes
want to use an interface, it has to do with an interface knowing if its using
the bonding driver or not (it shouldn't ever have to, but with your patch set,
its required to use the bonding api to create the interface and add slaves.

> and by providing a --vdev configuration options the user can still write their applications without any knowledge of the additional link bonding programmatic interface. If in the future a use case does emerge which requires multi-process control of bonded devices, I think it would make sense then to add an additional library to provide this functionality.

How exactly does that happen?  At what point does the bonding library in its
current form register a driver with rte_ethdev without the application first
calling some function in the bonding library to do so.  Because until that
happens, --vdev is non functional for this pmd.

FWIW, the concern for me here is one of packaging.  I don't want users to have
to pull in a library that they don't absolutely need.  the way you have this put
together right now, they need the entire bonding library even if they just want
a statically configured bond interface

Neil


> 
> Regards
> Declan
> --------------------------------------------------------------
> Intel Shannon Limited
> Registered in Ireland
> Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
> Registered Number: 308263
> Business address: Dromore House, East Park, Shannon, Co. Clare
> 
> This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.
> 
> 
> 

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
  2014-06-06  9:07       ` Doherty, Declan
@ 2014-06-06 15:13         ` Stephen Hemminger
  0 siblings, 0 replies; 127+ messages in thread
From: Stephen Hemminger @ 2014-06-06 15:13 UTC (permalink / raw)
  To: Doherty, Declan; +Cc: dev

On Fri, 6 Jun 2014 09:07:23 +0000
"Doherty, Declan" <declan.doherty@intel.com> wrote:

> > -----Original Message-----
> > From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> > Sent: Thursday, June 5, 2014 4:16 PM
> > To: Doherty, Declan
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
> > 
> > On Wed,  4 Jun 2014 16:18:02 +0100
> > declan.doherty@intel.com wrote:
> > 
> > > From: Declan Doherty <declan.doherty@intel.com>
> > >
> > > - Broadcast TX burst broadcast bug fix
> > > - Add/remove slave behavior fix
> > > - Checkpatch fixes
> > >
> > > Signed-off-by: Declan Doherty <declan.doherty@intel.com>
> > 
> > There are some pretty weak hash functions in there.
> > 
> > What about using:
> > .....
> 
> Hi Stephen,
> 
> I suppose the naming of these as hash functions is probably misleading, the aim is not to create a unique hash for each flow with minimal collisions but to  help balance traffic flows across the slaves of the bonded device, and as we are doing a modulus calculation based on the number of slaves attached, which I believe will typically be in the 2-4 range, I'm not sure that a stronger hashing function will give a better balance of flows across the slaves. For example in the Linux kernel implementation of the link bonding driver the mac hashing only uses the last byte of src & dst mac addresses to calculate it's eth hash.
> 
> /* L2 hash helper */
> static inline u32 bond_eth_hash(struct sk_buff *skb)
> {
> 	struct ethhdr *data = (struct ethhdr *)skb->data;
> 
> 	if (skb_headlen(skb) >= offsetof(struct ethhdr, h_proto))
> 		return data->h_dest[5] ^ data->h_source[5];
> 
> 	return 0;
> }
> 
> I'll investigate and see if a stronger hashing function will result in a better balancing of flows.
> --------------------------------------------------------------
> Intel Shannon Limited
> Registered in Ireland
> Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
> Registered Number: 308263
> Business address: Dromore House, East Park, Shannon, Co. Clare
> 
> This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.
> 
> 

The ether hash is very quick using multplicative hash on 64 bit value.

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
  2014-06-04 15:18   ` [dpdk-dev] [PATCH v2 1/4] " declan.doherty
  2014-06-04 15:18     ` declan.doherty
  2014-06-05 15:15     ` Stephen Hemminger
@ 2014-06-09 21:11     ` Eric Kinzie
  2014-06-13 14:03       ` Doherty, Declan
  2 siblings, 1 reply; 127+ messages in thread
From: Eric Kinzie @ 2014-06-09 21:11 UTC (permalink / raw)
  To: Declan Doherty; +Cc: dev

On Wed Jun 04 16:18:53 +0100 2014, Declan Doherty wrote:
> - Broadcast TX burst broadcast bug fix
> - Add/remove slave behavior fix
> - Checkpatch fixes

Declan, would you consider the following change to rte_bond.c?  The two
header files from librte_cmdline don't seem to be necessary.

 Eric


--- a/lib/librte_bond/rte_bond.c
+++ b/lib/librte_bond/rte_bond.c
@@ -44,9 +44,6 @@
 #include <rte_ip.h>
 #include <rte_udp.h>
 
-#include <cmdline_parse.h>
-#include <cmdline_parse_etheraddr.h>
-
 #include "rte_bond.h"
 
 static const char *driver_name = "Link Bonding PMD";

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
                     ` (8 preceding siblings ...)
  2014-06-06  3:26   ` Cao, Waterman
@ 2014-06-11 16:33   ` Thomas Monjalon
  2014-06-13 14:08     ` Doherty, Declan
  9 siblings, 1 reply; 127+ messages in thread
From: Thomas Monjalon @ 2014-06-11 16:33 UTC (permalink / raw)
  To: declan.doherty; +Cc: dev

Hi Declan,

Do you think you can send another version of your serie soon?
Some comments need to be addressed.

2 formatting comments:
- I saw some strange alignments of comments
- you should send your patches as children of the cover letter

Thanks
-- 
Thomas

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
  2014-06-09 21:11     ` Eric Kinzie
@ 2014-06-13 14:03       ` Doherty, Declan
  0 siblings, 0 replies; 127+ messages in thread
From: Doherty, Declan @ 2014-06-13 14:03 UTC (permalink / raw)
  To: Eric Kinzie; +Cc: dev

> -----Original Message-----
> From: Eric Kinzie [mailto:ehkinzie@gmail.com]
> Sent: Monday, June 9, 2014 10:11 PM
> To: Doherty, Declan
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 1/4] Link Bonding Library
> 
> On Wed Jun 04 16:18:53 +0100 2014, Declan Doherty wrote:
> > - Broadcast TX burst broadcast bug fix
> > - Add/remove slave behavior fix
> > - Checkpatch fixes
> 
> Declan, would you consider the following change to rte_bond.c?  The two
> header files from librte_cmdline don't seem to be necessary.
> 
>  Eric
> 
> 
> --- a/lib/librte_bond/rte_bond.c
> +++ b/lib/librte_bond/rte_bond.c
> @@ -44,9 +44,6 @@
>  #include <rte_ip.h>
>  #include <rte_udp.h>
> 
> -#include <cmdline_parse.h>
> -#include <cmdline_parse_etheraddr.h>
> -
>  #include "rte_bond.h"
> 
>  static const char *driver_name = "Link Bonding PMD";

Hi Eric, 
I've cleaned up the includes in v3 of the patch, but the those headers are now actually required for the kvarg parsing.

Regards
Declan

^ permalink raw reply	[flat|nested] 127+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
  2014-06-11 16:33   ` Thomas Monjalon
@ 2014-06-13 14:08     ` Doherty, Declan
  2014-06-13 15:15       ` Thomas Monjalon
  0 siblings, 1 reply; 127+ messages in thread
From: Doherty, Declan @ 2014-06-13 14:08 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, June 11, 2014 5:33 PM
> To: Doherty, Declan
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 0/4] Link Bonding Library
> 
> Hi Declan,
> 
> Do you think you can send another version of your serie soon?
> Some comments need to be addressed.
> 
> 2 formatting comments:
> - I saw some strange alignments of comments
> - you should send your patches as children of the cover letter
> 
> Thanks
> --
> Thomas

Hi Thomas, 
I've just submitted v3 of the patch, which should address the majority of the comments and any formatting issues.

Regards
Declan

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v3 0/5] Link Bonding PMD Library
  2014-05-28 15:32 [dpdk-dev] [PATCH 0/4] Link Bonding Library declan.doherty
                   ` (6 preceding siblings ...)
  2014-06-04 15:18 ` [dpdk-dev] [PATCH v2 " declan.doherty
@ 2014-06-13 14:41 ` Declan Doherty
  2014-06-13 14:41   ` [dpdk-dev] [PATCH v3 1/5] " Declan Doherty
                     ` (12 more replies)
  7 siblings, 13 replies; 127+ messages in thread
From: Declan Doherty @ 2014-06-13 14:41 UTC (permalink / raw)
  To: dev, dev

This patch contains the initial release of the Link Bonding PMD Library

Supporting bonding modes:
 0 - Round Robin
 1 - Active Backup
 2 - Balance (Supporting 3 transmission polices)
	layer 2, layer 2+3, layer 3+4
 3 - Broadcast


Version 3 of this patch set add the following functionality changes
 - Link bonding command line option parsing / initialization support
 - Unique name identifier to rte_eth_dev_data struct to identify
   virtual ethdev's which are to be added to bondded device from
   command line.
 - Updates to EAL to support initialization of link bonding devices

Patch Set Description:
 0001 - librte_pmd_bond + makefile changes
 0002 - librte_eal / librte_ether changes to support bonding device intialization
 0003 - link bonding unti test suite
 0004 - testpmd link bonding support changes
 0005 - doxygen additions


 app/test-pmd/cmdline.c                      |  571 ++++
 app/test-pmd/config.c                       |    4 +-
 app/test-pmd/parameters.c                   |    3 +
 app/test-pmd/testpmd.c                      |   37 +-
 app/test-pmd/testpmd.h                      |    2 +
 app/test/Makefile                           |    4 +-
 app/test/commands.c                         |    7 +
 app/test/packet_burst_generator.c           |  288 ++
 app/test/packet_burst_generator.h           |   78 +
 app/test/test.h                             |    1 +
 app/test/test_link_bonding.c                | 3958 +++++++++++++++++++++++++++
 app/test/virtual_pmd.c                      |  574 ++++
 app/test/virtual_pmd.h                      |   74 +
 config/common_bsdapp                        |    5 +
 config/common_linuxapp                      |    5 +
 doc/doxy-api-index.md                       |    1 +
 doc/doxy-api.conf                           |    1 +
 lib/Makefile                                |    1 +
 lib/librte_eal/common/eal_common_dev.c      |   66 +-
 lib/librte_eal/common/eal_common_pci.c      |    6 +
 lib/librte_eal/common/include/eal_private.h |    7 +
 lib/librte_eal/common/include/rte_dev.h     |    1 +
 lib/librte_ether/rte_ethdev.c               |   34 +-
 lib/librte_ether/rte_ethdev.h               |    7 +-
 lib/librte_pmd_bond/Makefile                |   32 +
 lib/librte_pmd_bond/rte_eth_bond.c          | 2149 +++++++++++++++
 lib/librte_pmd_bond/rte_eth_bond.h          |  255 ++
 lib/librte_pmd_pcap/rte_eth_pcap.c          |   22 +-
 lib/librte_pmd_ring/rte_eth_ring.c          |   32 +-
 lib/librte_pmd_ring/rte_eth_ring.h          |    3 +-
 lib/librte_pmd_xenvirt/rte_eth_xenvirt.c    |    2 +-
 mk/rte.app.mk                               |    5 +
 32 files changed, 8192 insertions(+), 43 deletions(-)
 create mode 100644 app/test/packet_burst_generator.c
 create mode 100644 app/test/packet_burst_generator.h
 create mode 100644 app/test/test_link_bonding.c
 create mode 100644 app/test/virtual_pmd.c
 create mode 100644 app/test/virtual_pmd.h
 create mode 100644 lib/librte_pmd_bond/Makefile
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond.c
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond.h

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v3 1/5] Link Bonding PMD Library
  2014-06-13 14:41 ` [dpdk-dev] [PATCH v3 0/5] Link Bonding PMD Library Declan Doherty
@ 2014-06-13 14:41   ` Declan Doherty
  2014-06-13 14:41   ` [dpdk-dev] [PATCH v3 2/5] Link Bonding PMD Library (librte_eal/librte_ether link bonding support changes) Declan Doherty
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 127+ messages in thread
From: Declan Doherty @ 2014-06-13 14:41 UTC (permalink / raw)
  To: dev, dev

Link Bonding Library (lib/librte_pmd_bond) initial release with support for
 Mode 0 - Round Robin
 Mode 1 - Active Backup
 Mode 2 - Balance -> Supports 3 transmit polices (layer 2, layer 2+3, layer 3+4)
 Mode 3 - Broadcast


Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 config/common_bsdapp               |    5 +
 config/common_linuxapp             |    5 +
 lib/Makefile                       |    1 +
 lib/librte_pmd_bond/Makefile       |   32 +
 lib/librte_pmd_bond/rte_eth_bond.c | 2149 ++++++++++++++++++++++++++++++++++++
 lib/librte_pmd_bond/rte_eth_bond.h |  255 +++++
 mk/rte.app.mk                      |    5 +
 7 files changed, 2452 insertions(+)
 create mode 100644 lib/librte_pmd_bond/Makefile
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond.c
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond.h

diff --git a/config/common_bsdapp b/config/common_bsdapp
index ec7b159..545d760 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -187,6 +187,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=y
 
 #
+# Compile link bonding pmd library
+#
+CONFIG_RTE_LIBRTE_PMD_BOND=y
+
+#
 # Do prefetch of packet data within PMD driver receive function
 #
 CONFIG_RTE_PMD_PACKET_PREFETCH=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 7c143eb..eb2e3d0 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -216,6 +216,11 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
 CONFIG_RTE_LIBRTE_PMD_PCAP=n
 
 #
+# Compile link bonding pmd library
+#
+CONFIG_RTE_LIBRTE_PMD_BOND=y
+
+#
 # Compile Xen PMD
 #
 CONFIG_RTE_LIBRTE_PMD_XENVIRT=n
diff --git a/lib/Makefile b/lib/Makefile
index 8cdfa7d..66232a9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -47,6 +47,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += librte_pmd_pcap
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += librte_pmd_vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += librte_pmd_xenvirt
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += librte_pmd_bond
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
 DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net
diff --git a/lib/librte_pmd_bond/Makefile b/lib/librte_pmd_bond/Makefile
new file mode 100644
index 0000000..9275830
--- /dev/null
+++ b/lib/librte_pmd_bond/Makefile
@@ -0,0 +1,32 @@
+# <COPYRIGHT_TAG>
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_bond.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond.c
+
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_eth_bond.h
+
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += lib/librte_malloc
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_bond/rte_eth_bond.c b/lib/librte_pmd_bond/rte_eth_bond.c
new file mode 100644
index 0000000..01d917d
--- /dev/null
+++ b/lib/librte_pmd_bond/rte_eth_bond.c
@@ -0,0 +1,2149 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <linux/binfmts.h>
+
+#include <rte_mbuf.h>
+#include <rte_cycles.h>
+#include <rte_dev.h>
+#include <rte_devargs.h>
+#include <rte_ethdev.h>
+#include <rte_ip.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_memory.h>
+#include <rte_udp.h>
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_etheraddr.h>
+
+#include "rte_eth_bond.h"
+
+/* Link Bonding KVARG option defintions for --vdev  */
+#define PMD_BOND_KVARG					("eth_bond")
+
+#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_XMIT_POLICY_LAYER2_KVARG	("l2")
+#define PMD_BOND_XMIT_POLICY_LAYER23_KVARG	("l23")
+#define PMD_BOND_XMIT_POLICY_LAYER34_KVARG	("l34")
+
+static const char *pmd_bond_init_valid_arguments[] = {
+	PMD_BOND_SLAVE_PORT_KVARG,
+	PMD_BOND_PRIMARY_SLAVE_KVARG,
+	PMD_BOND_MODE_KVARG,
+	PMD_BOND_XMIT_POLICY_KVARG,
+	PMD_BOND_SOCKET_ID_KVARG,
+	PMD_BOND_MAC_ADDR_KVARG,
+
+	NULL
+};
+
+static const char *driver_name = "Link Bonding PMD";
+
+/** Port Queue Mapping Structure */
+struct bond_rx_queue {
+	int queue_id;
+	/**< Queue Id */
+	struct bond_dev_private *dev_private;
+	/**< Reference to eth_dev private structure */
+	uint16_t nb_rx_desc;
+	/**< Number of RX descriptors available for the queue */
+	struct rte_eth_rxconf rx_conf;
+	/**< Copy of RX configuration structure for queue */
+	struct rte_mempool *mb_pool;
+	/**< Reference to mbuf pool to use for RX queue */
+};
+
+struct bond_tx_queue {
+	int queue_id;
+	/**< Queue Id */
+	struct bond_dev_private *dev_private;
+	/**< Reference to dev private structure */
+	uint16_t nb_tx_desc;
+	/**< Number of TX descriptors available for the queue */
+	struct rte_eth_txconf tx_conf;
+	/**< 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 */
+};
+
+/** Link Bonding PMD device private configuration Structure */
+struct bond_dev_private {
+	uint8_t mode;						/**< Link Bonding Mode */
+
+	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;
+	/**< Flag for whether MAC address is user defined or not */
+	uint8_t promiscuous_en;
+	/**< Enabled/disable promiscuous mode on slave devices */
+	uint8_t link_props_set;
+	/**< Bonded eth_dev link properties set */
+
+	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_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];
+};
+
+static struct slave_conf *
+slave_config_get(struct bond_dev_private *internals, uint8_t slave_port_id);
+
+static int
+valid_bonded_ethdev(struct rte_eth_dev *eth_dev)
+{
+	size_t len;
+
+	/* Check valid pointer */
+	if (eth_dev->driver->pci_drv.name == NULL || driver_name == NULL)
+		return -1;
+
+	/* Check string lengths are equal */
+	len = strlen(driver_name);
+	if (strlen(eth_dev->driver->pci_drv.name) != len)
+		return -1;
+
+	/* Compare strings */
+	return strncmp(eth_dev->driver->pci_drv.name, driver_name, len);
+}
+
+static int
+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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+valid_bonded_port_id(uint8_t port_id)
+{
+	/* Verify that port id's are valid */
+	if (valid_port_id(port_id))
+		return -1;
+
+	/* 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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+valid_slave_port_id(uint8_t port_id)
+{
+	/* Verify that port id's are valid */
+	if (valid_port_id(port_id))
+		return -1;
+
+	/* Verify that port_id refers to a non bonded port */
+	if (!valid_bonded_ethdev(&rte_eth_devices[port_id]))
+		return -1;
+
+	return 0;
+}
+
+
+static uint16_t
+bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+
+	uint16_t num_rx_slave = 0;
+	uint16_t num_rx_total = 0;
+
+	int i;
+
+	/* Cast to structure, containing bonded device's port id and queue id */
+	struct bond_rx_queue *bd_rx_q = (struct bond_rx_queue *)queue;
+
+	internals = bd_rx_q->dev_private;
+
+	switch (internals->mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BROADCAST:
+	case BONDING_MODE_BALANCE:
+		for (i = 0; i < internals->active_slave_count; i++) {
+			/* Offset of pointer to *bufs increases as packets are received
+			 * from other slaves */
+			num_rx_slave = rte_eth_rx_burst(internals->active_slaves[i],
+					bd_rx_q->queue_id, bufs + num_rx_total, nb_pkts);
+			if (num_rx_slave)
+				num_rx_total += num_rx_slave;
+		}
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+		num_rx_slave = rte_eth_rx_burst(internals->current_primary_port,
+				bd_rx_q->queue_id, bufs, nb_pkts);
+		if (num_rx_slave)
+			num_rx_total = num_rx_slave;
+		break;
+	}
+	return num_rx_total;
+}
+
+
+static uint16_t
+bond_ethdev_tx_round_robin(void *queue, struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	struct bond_dev_private *dev_private;
+	struct bond_tx_queue *bd_tx_q;
+
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS][nb_pkts];
+	uint16_t slave_nb_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	static int last_slave_idx = -1;
+	int i, slave_idx;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	dev_private = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = dev_private->active_slave_count;
+	memcpy(slaves, dev_private->active_slaves,
+			sizeof(dev_private->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return num_tx_total;
+
+	/* Populate slaves mbuf with which packets are to be sent on it  */
+	for (i = 0; i < nb_pkts; i++) {
+		slave_idx = i % num_of_slaves;
+		slave_bufs[slave_idx][(slave_nb_pkts[slave_idx])++] = bufs[i];
+	}
+
+	/* calculate the next slave to transmit on based on the last slave idx used
+	 * in the last call to bond_ethdev_tx_burst_round_robin */
+	slave_idx = last_slave_idx + 1;
+
+	/* Send packet burst on each slave device */
+	for (i = 0; i < num_of_slaves; i++) {
+		slave_idx = (slave_idx + i) % num_of_slaves;
+
+		if (slave_nb_pkts[i] > 0) {
+			num_tx_total += rte_eth_tx_burst(slaves[slave_idx],
+					bd_tx_q->queue_id, slave_bufs[i], slave_nb_pkts[i]);
+		}
+	}
+
+	last_slave_idx = slave_idx;
+
+	return num_tx_total;
+}
+
+static uint16_t bond_ethdev_tx_active_backup(void *queue,
+		struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	if (internals->active_slave_count < 1)
+		return 0;
+
+	return rte_eth_tx_burst(internals->current_primary_port, bd_tx_q->queue_id,
+			bufs, nb_pkts);
+}
+
+
+static inline uint16_t
+ether_hash(struct ether_hdr *eth_hdr)
+{
+	uint16_t *word_src_addr = (uint16_t *)eth_hdr->s_addr.addr_bytes;
+	uint16_t *word_dst_addr = (uint16_t *)eth_hdr->d_addr.addr_bytes;
+
+	return (word_src_addr[0] ^ word_dst_addr[0]) ^
+			(word_src_addr[1] ^ word_dst_addr[1]) ^
+			(word_src_addr[2] ^ word_dst_addr[2]);
+}
+
+static inline uint32_t
+ipv4_hash(struct ipv4_hdr *ipv4_hdr)
+{
+	return (ipv4_hdr->src_addr ^ ipv4_hdr->dst_addr);
+}
+
+static inline uint32_t
+ipv6_hash(struct ipv6_hdr *ipv6_hdr)
+{
+	uint32_t *word_src_addr = (uint32_t *)&(ipv6_hdr->src_addr[0]);
+	uint32_t *word_dst_addr = (uint32_t *)&(ipv6_hdr->dst_addr[0]);
+
+	return (word_src_addr[0] ^ word_dst_addr[0]) ^
+			(word_src_addr[1] ^ word_dst_addr[1]) ^
+			(word_src_addr[2] ^ word_dst_addr[2]) ^
+			(word_src_addr[3] ^ word_dst_addr[3]);
+}
+
+static uint32_t
+udp_hash(struct udp_hdr *hdr)
+{
+	return hdr->src_port ^ hdr->dst_port;
+}
+
+static inline uint16_t
+xmit_slave_hash(const struct rte_mbuf *buf, uint8_t slave_count, uint8_t policy)
+{
+	struct ether_hdr *eth_hdr;
+	struct udp_hdr *udp_hdr;
+	size_t eth_offset = 0;
+	uint32_t hash = 0;
+
+	if (slave_count == 1)
+		return 0;
+
+	switch (policy) {
+	case BALANCE_XMIT_POLICY_LAYER2:
+		eth_hdr = (struct ether_hdr *)buf->pkt.data;
+
+		hash = ether_hash(eth_hdr);
+		hash ^= hash >> 8;
+		return hash % slave_count;
+
+
+	case BALANCE_XMIT_POLICY_LAYER23:
+		eth_hdr = (struct ether_hdr *)buf->pkt.data;
+
+		if (buf->ol_flags & PKT_RX_VLAN_PKT)
+			eth_offset = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_offset = sizeof(struct ether_hdr);
+
+		if (buf->ol_flags & PKT_RX_IPV4_HDR) {
+			struct ipv4_hdr *ipv4_hdr;
+			ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(buf,
+					unsigned char *) + eth_offset);
+
+			hash = ether_hash(eth_hdr) ^ ipv4_hash(ipv4_hdr);
+
+		} else {
+			struct ipv6_hdr *ipv6_hdr;
+
+			ipv6_hdr = (struct ipv6_hdr *)(rte_pktmbuf_mtod(buf,
+					unsigned char *) + eth_offset);
+
+			hash = ether_hash(eth_hdr) ^ ipv6_hash(ipv6_hdr);
+		}
+		break;
+
+	case BALANCE_XMIT_POLICY_LAYER34:
+		if (buf->ol_flags & PKT_RX_VLAN_PKT)
+			eth_offset = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_offset = sizeof(struct ether_hdr);
+
+		if (buf->ol_flags & PKT_RX_IPV4_HDR) {
+			struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)
+					(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset);
+
+			if (ipv4_hdr->next_proto_id == IPPROTO_UDP) {
+				udp_hdr = (struct udp_hdr *)
+						(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset +
+								sizeof(struct ipv4_hdr));
+				hash = ipv4_hash(ipv4_hdr) ^ udp_hash(udp_hdr);
+			} else {
+				hash = ipv4_hash(ipv4_hdr);
+			}
+		} else {
+			struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)
+					(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset);
+
+			if (ipv6_hdr->proto == IPPROTO_UDP) {
+				udp_hdr = (struct udp_hdr *)
+						(rte_pktmbuf_mtod(buf, unsigned char *) + eth_offset +
+								sizeof(struct ipv6_hdr));
+				hash = ipv6_hash(ipv6_hdr) ^ udp_hash(udp_hdr);
+			} else {
+				hash = ipv6_hash(ipv6_hdr);
+			}
+		}
+		break;
+	}
+
+	hash ^= hash >> 16;
+	hash ^= hash >> 8;
+
+	return hash % slave_count;
+}
+
+static uint16_t
+bond_ethdev_tx_balance(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	int i, op_slave_id;
+
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS][nb_pkts];
+	uint16_t slave_nb_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = internals->active_slave_count;
+	memcpy(slaves, internals->active_slaves,
+			sizeof(internals->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return num_tx_total;
+
+
+	/* Populate slaves mbuf with the packets which are to be sent on it  */
+	for (i = 0; i < nb_pkts; i++) {
+		/* Select output slave using hash based on xmit policy */
+		op_slave_id = xmit_slave_hash(bufs[i], num_of_slaves,
+				internals->balance_xmit_policy);
+
+		/* Populate slave mbuf arrays with mbufs for that slave */
+		slave_bufs[op_slave_id][slave_nb_pkts[op_slave_id]++] = bufs[i];
+	}
+
+	/* Send packet burst on each slave device */
+	for (i = 0; i < num_of_slaves; i++) {
+		if (slave_nb_pkts[i] > 0) {
+			num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
+					slave_bufs[i], slave_nb_pkts[i]);
+		}
+	}
+
+	return num_tx_total;
+}
+
+static uint16_t
+bond_ethdev_tx_burst_broadcast(void *queue, struct rte_mbuf **bufs,
+		uint16_t nb_pkts)
+{
+	struct bond_dev_private *internals;
+	struct bond_tx_queue *bd_tx_q;
+
+	uint8_t num_of_slaves;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	uint16_t num_tx_total = 0;
+
+	int i;
+
+	bd_tx_q = (struct bond_tx_queue *)queue;
+	internals = bd_tx_q->dev_private;
+
+	/* Copy slave list to protect against slave up/down changes during tx
+	 * bursting */
+	num_of_slaves = internals->active_slave_count;
+	memcpy(slaves, internals->active_slaves,
+			sizeof(internals->active_slaves[0]) * num_of_slaves);
+
+	if (num_of_slaves < 1)
+		return 0;
+
+	/* Increment reference count on mbufs */
+	for (i = 0; i < nb_pkts; i++)
+		rte_mbuf_refcnt_update(bufs[i], num_of_slaves - 1);
+
+	/* Transmit burst on each active slave */
+	for (i = 0; i < num_of_slaves; i++)
+		num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
+				bufs, nb_pkts);
+
+	return num_tx_total;
+}
+
+static void
+link_properties_set(struct rte_eth_dev *bonded_eth_dev,
+		struct rte_eth_link *slave_dev_link)
+{
+	struct rte_eth_link *bonded_dev_link = &bonded_eth_dev->data->dev_link;
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	if (slave_dev_link->link_status &&
+		bonded_eth_dev->data->dev_started) {
+		bonded_dev_link->link_duplex = slave_dev_link->link_duplex;
+		bonded_dev_link->link_speed = slave_dev_link->link_speed;
+
+		internals->link_props_set = 1;
+	}
+}
+
+static void
+link_properties_reset(struct rte_eth_dev *bonded_eth_dev)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	memset(&(bonded_eth_dev->data->dev_link), 0,
+			sizeof(bonded_eth_dev->data->dev_link));
+
+	internals->link_props_set = 0;
+}
+
+static int
+link_properties_valid(struct rte_eth_link *bonded_dev_link,
+		struct rte_eth_link *slave_dev_link)
+{
+	if (bonded_dev_link->link_duplex != slave_dev_link->link_duplex ||
+		bonded_dev_link->link_speed !=  slave_dev_link->link_speed)
+		return -1;
+
+	return 0;
+}
+
+static int
+mac_address_set(struct rte_eth_dev *eth_dev, struct ether_addr *new_mac_addr)
+{
+	struct ether_addr *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__);
+		return -1;
+	}
+
+	if (new_mac_addr == NULL) {
+		RTE_LOG(ERR, PMD, "%s: NULL pointer MAC specified\n", __func__);
+		return -1;
+	}
+
+	/* 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));
+
+	return 0;
+}
+
+static int
+mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+	int i;
+
+	/* Update slave devices MAC addresses */
+	if (internals->slave_count < 1)
+		return -1;
+
+	switch (internals->mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+	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]],
+					bonded_eth_dev->data->mac_addrs)) {
+				RTE_LOG(ERR, PMD,
+						"%s: Failed to update port Id %d MAC address\n",
+						__func__, internals->slaves[i]);
+				return -1;
+			}
+		}
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		for (i = 0; i < internals->slave_count; i++) {
+			if (internals->slaves[i] == 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);
+				}
+			} 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]);
+
+
+					return -1;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+static int
+bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
+{
+	struct bond_dev_private *internals;
+
+	internals = eth_dev->data->dev_private;
+
+	switch (mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_round_robin;
+		break;
+	case BONDING_MODE_ACTIVE_BACKUP:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_active_backup;
+		break;
+	case BONDING_MODE_BALANCE:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_balance;
+		break;
+	case BONDING_MODE_BROADCAST:
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_broadcast;
+		break;
+	default:
+		return -1;
+	}
+	internals->mode = mode;
+
+	return 0;
+}
+
+static int
+slave_configure(struct rte_eth_dev *bonded_eth_dev,
+		struct rte_eth_dev *slave_eth_dev)
+{
+	struct bond_rx_queue *bd_rx_q;
+	struct bond_tx_queue *bd_tx_q;
+
+	int 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;
+
+	if (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;
+	}
+
+	/* 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,
+				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;
+		}
+	}
+
+	/* Setup Tx Queues */
+	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,
+				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;
+		}
+	}
+
+	/* 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);
+		return -1;
+	}
+
+	return 0;
+}
+
+static 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;
+}
+
+static void
+slave_config_clear(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) {
+			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]));
+		}
+	}
+}
+
+static void
+slave_config_store(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];
+
+	presisted_slave_conf->port_id = slave_eth_dev->data->port_id;
+
+	memcpy(&(presisted_slave_conf->mac_addr), slave_eth_dev->data->mac_addrs,
+			sizeof(struct ether_addr));
+}
+
+
+
+static void
+bond_ethdev_primary_set(struct bond_dev_private *internals,
+		uint8_t slave_port_id)
+{
+	int i;
+
+	if (internals->active_slave_count < 1)
+		internals->current_primary_port = slave_port_id;
+	else
+		/* Search bonded device slave ports for new proposed primary port */
+		for (i = 0; i < internals->active_slave_count; i++) {
+			if (internals->active_slaves[i] == slave_port_id)
+				internals->current_primary_port = slave_port_id;
+		}
+}
+
+static void
+bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev);
+
+static int
+bond_ethdev_start(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals;
+	int i;
+
+	/* 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);
+		return -1;
+	}
+
+	eth_dev->data->dev_link.link_status = 1;
+	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__);
+		return -1;
+	}
+
+	if (internals->user_defined_mac == 0) {
+		struct slave_conf *conf = slave_config_get(internals,
+				internals->primary_port);
+
+		if (mac_address_set(eth_dev, &(conf->mac_addr)) != 0) {
+			RTE_LOG(ERR, PMD,
+					"bonded port (%d) failed to update mac address",
+					eth_dev->data->port_id);
+			return -1;
+		}
+	}
+
+	/* Update all slave devices MACs*/
+	if (mac_address_slaves_update(eth_dev) != 0)
+		return -1;
+
+	/* If bonded device is configure in promiscuous mode then re-apply config */
+	if (internals->promiscuous_en)
+		bond_ethdev_promiscuous_enable(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)",
+					eth_dev->data->port_id, internals->slaves[i]);
+			return -1;
+		}
+	}
+
+	if (internals->user_defined_primary_port)
+		bond_ethdev_primary_set(internals, internals->primary_port);
+
+	return 0;
+}
+
+static void
+bond_ethdev_stop(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals = eth_dev->data->dev_private;
+
+	internals->active_slave_count = 0;
+
+	eth_dev->data->dev_link.link_status = 0;
+	eth_dev->data->dev_started = 0;
+}
+
+static void
+bond_ethdev_close(struct rte_eth_dev *dev __rte_unused)
+{
+}
+
+static int
+bond_ethdev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static void
+bond_ethdev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
+{
+	dev_info->driver_name = driver_name;
+	dev_info->max_mac_addrs = 1;
+
+	dev_info->max_rx_pktlen = (uint32_t)2048;
+
+	dev_info->max_rx_queues = (uint16_t)128;
+	dev_info->max_tx_queues = (uint16_t)512;
+
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = dev->pci_dev;
+}
+
+static int
+bond_ethdev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_rx_desc, unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool)
+{
+	struct bond_rx_queue *bd_rx_q = (struct bond_rx_queue *)
+			rte_zmalloc_socket(NULL, sizeof(struct bond_rx_queue),
+					0, dev->pci_dev->numa_node);
+	if (bd_rx_q == NULL)
+		return -1;
+
+	bd_rx_q->queue_id = rx_queue_id;
+	bd_rx_q->dev_private = dev->data->dev_private;
+
+	bd_rx_q->nb_rx_desc = nb_rx_desc;
+
+	memcpy(&(bd_rx_q->rx_conf), rx_conf, sizeof(struct rte_eth_rxconf));
+	bd_rx_q->mb_pool = mb_pool;
+
+	dev->data->rx_queues[rx_queue_id] = bd_rx_q;
+
+	return 0;
+}
+
+static int
+bond_ethdev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_tx_desc, unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf)
+{
+	struct bond_tx_queue *bd_tx_q  = (struct bond_tx_queue *)
+			rte_zmalloc_socket(NULL, sizeof(struct bond_tx_queue),
+					0, dev->pci_dev->numa_node);
+
+	if (bd_tx_q == NULL)
+			return -1;
+
+	bd_tx_q->queue_id = tx_queue_id;
+	bd_tx_q->dev_private = dev->data->dev_private;
+
+	bd_tx_q->nb_tx_desc = nb_tx_desc;
+	memcpy(&(bd_tx_q->tx_conf), tx_conf, sizeof(bd_tx_q->tx_conf));
+
+	dev->data->tx_queues[tx_queue_id] = bd_tx_q;
+
+	return 0;
+}
+
+static void
+bond_ethdev_rx_queue_release(void *queue)
+{
+	if (queue == NULL)
+		return;
+
+	rte_free(queue);
+}
+
+static void
+bond_ethdev_tx_queue_release(void *queue)
+{
+	if (queue == NULL)
+		return;
+
+	rte_free(queue);
+}
+
+
+static int
+bond_ethdev_link_update(struct rte_eth_dev *bonded_eth_dev,
+		int wait_to_complete)
+{
+	struct bond_dev_private *internals = bonded_eth_dev->data->dev_private;
+
+	if (!bonded_eth_dev->data->dev_started ||
+		internals->active_slave_count == 0) {
+		bonded_eth_dev->data->dev_link.link_status = 0;
+		return 0;
+	} else {
+		struct rte_eth_dev *slave_eth_dev;
+		int i, link_up = 0;
+
+		for (i = 0; i < internals->active_slave_count; i++) {
+			slave_eth_dev = &rte_eth_devices[internals->active_slaves[i]];
+
+			(*slave_eth_dev->dev_ops->link_update)(slave_eth_dev,
+					wait_to_complete);
+			if (slave_eth_dev->data->dev_link.link_status == 1) {
+				link_up = 1;
+				break;
+			}
+		}
+
+		bonded_eth_dev->data->dev_link.link_status = link_up;
+	}
+
+	return 0;
+}
+
+static void
+bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	struct rte_eth_stats slave_stats;
+
+	int i;
+
+	/* clear bonded stats before populating from slaves */
+	memset(stats, 0, sizeof(*stats));
+
+	for (i = 0; i < internals->slave_count; i++) {
+		rte_eth_stats_get(internals->slaves[i], &slave_stats);
+
+		stats->ipackets += slave_stats.ipackets;
+		stats->opackets += slave_stats.opackets;
+		stats->ibytes += slave_stats.ibytes;
+		stats->obytes += slave_stats.obytes;
+		stats->ierrors += slave_stats.ierrors;
+		stats->oerrors += slave_stats.oerrors;
+		stats->imcasts += slave_stats.imcasts;
+		stats->rx_nombuf += slave_stats.rx_nombuf;
+		stats->fdirmatch += slave_stats.fdirmatch;
+		stats->fdirmiss += slave_stats.fdirmiss;
+		stats->tx_pause_xon += slave_stats.tx_pause_xon;
+		stats->rx_pause_xon += slave_stats.rx_pause_xon;
+		stats->tx_pause_xoff += slave_stats.tx_pause_xoff;
+		stats->rx_pause_xoff += slave_stats.rx_pause_xoff;
+	}
+}
+
+static void
+bond_ethdev_stats_reset(struct rte_eth_dev *dev)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < internals->slave_count; i++)
+		rte_eth_stats_reset(internals->slaves[i]);
+}
+
+static void
+bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
+{
+	struct bond_dev_private *internals = eth_dev->data->dev_private;
+	int i;
+
+	internals->promiscuous_en = 1;
+
+	switch (internals->mode) {
+	/* Promiscuous mode is propagated to all slaves */
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BALANCE:
+	case BONDING_MODE_BROADCAST:
+		for (i = 0; i < internals->slave_count; i++)
+			rte_eth_promiscuous_enable(internals->slaves[i]);
+		break;
+	/* Promiscuous mode is propagated only to primary slave */
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		rte_eth_promiscuous_enable(internals->current_primary_port);
+
+	}
+}
+
+static void
+bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct bond_dev_private *internals = dev->data->dev_private;
+	int i;
+
+	internals->promiscuous_en = 0;
+
+	switch (internals->mode) {
+	/* Promiscuous mode is propagated to all slaves */
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_BALANCE:
+	case BONDING_MODE_BROADCAST:
+		for (i = 0; i < internals->slave_count; i++)
+			rte_eth_promiscuous_disable(internals->slaves[i]);
+		break;
+	/* Promiscuous mode is propagated only to primary slave */
+	case BONDING_MODE_ACTIVE_BACKUP:
+	default:
+		rte_eth_promiscuous_disable(internals->current_primary_port);
+	}
+}
+
+
+static void
+bond_ethdev_lsc_event_callback(uint8_t port_id, enum rte_eth_event_type type,
+		void *param)
+{
+	struct rte_eth_dev *bonded_eth_dev, *slave_eth_dev;
+	struct bond_dev_private *internals;
+	struct rte_eth_link link;
+
+	int i, bonded_port_id, valid_slave, active_pos = -1;
+
+	if (type != RTE_ETH_EVENT_INTR_LSC)
+		return;
+
+	if (param == NULL)
+		return;
+
+	bonded_port_id = *(uint8_t *)param;
+
+	bonded_eth_dev = &rte_eth_devices[bonded_port_id];
+	slave_eth_dev = &rte_eth_devices[port_id];
+
+	if (valid_bonded_ethdev(bonded_eth_dev))
+		return;
+
+	internals = bonded_eth_dev->data->dev_private;
+
+	/* If the device isn't started don't handle interrupts */
+	if (!bonded_eth_dev->data->dev_started)
+		return;
+
+	/* 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) {
+			valid_slave = 1;
+			break;
+		}
+	}
+
+	if (!valid_slave)
+		return;
+
+	/* Search for port in active port list */
+	for (i = 0; i < internals->active_slave_count; i++) {
+		if (port_id == internals->active_slaves[i]) {
+			active_pos = i;
+			break;
+		}
+	}
+
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status) {
+		if (active_pos == -1) {
+			/* if no active slave ports then set this port to be primary port */
+			if (internals->active_slave_count == 0) {
+				/* If first active slave, then change link status */
+				bonded_eth_dev->data->dev_link.link_status = 1;
+				internals->current_primary_port = port_id;
+
+				/* Inherit eth dev link properties from first active slave */
+				link_properties_set(bonded_eth_dev,
+						&(slave_eth_dev->data->dev_link));
+
+			}
+			internals->active_slaves[internals->active_slave_count++] = port_id;
+
+			/* If user has defined the primary port then default to using it */
+			if (internals->user_defined_primary_port &&
+					internals->primary_port == port_id)
+				bond_ethdev_primary_set(internals, port_id);
+
+		}
+	} else {
+		if (active_pos != -1) {
+			/* Remove from active slave list */
+			for (i = active_pos; i < (internals->active_slave_count - 1); i++)
+				internals->active_slaves[i] = internals->active_slaves[i+1];
+
+			internals->active_slave_count--;
+
+			/* No active slaves, change link status to down and reset other
+			 * link properties */
+			if (internals->active_slave_count == 0)
+				link_properties_reset(bonded_eth_dev);
+
+			/* Update primary id, take first active slave from list or if none
+			 * available set to -1 */
+			if (port_id == internals->current_primary_port) {
+				if (internals->active_slave_count > 0)
+					bond_ethdev_primary_set(internals,
+							internals->active_slaves[0]);
+				else
+					internals->current_primary_port = internals->primary_port;
+			}
+		}
+	}
+}
+
+static struct eth_dev_ops default_dev_ops = {
+		.dev_start = bond_ethdev_start,
+		.dev_stop = bond_ethdev_stop,
+		.dev_close = bond_ethdev_close,
+		.dev_configure = bond_ethdev_configure,
+		.dev_infos_get = bond_ethdev_info,
+		.rx_queue_setup = bond_ethdev_rx_queue_setup,
+		.tx_queue_setup = bond_ethdev_tx_queue_setup,
+		.rx_queue_release = bond_ethdev_rx_queue_release,
+		.tx_queue_release = bond_ethdev_tx_queue_release,
+		.link_update = bond_ethdev_link_update,
+		.stats_get = bond_ethdev_stats_get,
+		.stats_reset = bond_ethdev_stats_reset,
+		.promiscuous_enable = bond_ethdev_promiscuous_enable,
+		.promiscuous_disable = bond_ethdev_promiscuous_disable
+};
+
+static uint8_t
+number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; ((i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL)); i++) {
+		if (sockets < ms[i].socket_id)
+			sockets = ms[i].socket_id;
+	}
+
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+
+}
+
+int
+rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
+{
+	struct rte_pci_device *pci_dev = NULL;
+	struct bond_dev_private *internals = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct eth_driver *eth_drv = NULL;
+	struct rte_pci_driver *pci_drv = NULL;
+	struct rte_pci_id *pci_id_table = NULL;
+	/* now do all data allocation - for eth_dev structure, dummy pci driver
+	 * and internal (private) data
+	 */
+
+	if (name == NULL) {
+		RTE_LOG(ERR, PMD, "Invalid name specified\n");
+		goto err;
+	}
+
+	if (socket_id >= number_of_sockets()) {
+		RTE_LOG(ERR, PMD,
+				"%s: invalid socket id specified to create bonded device on.\n",
+				__func__);
+		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");
+		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");
+		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");
+		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");
+		goto err;
+	}
+
+	pci_drv->id_table = pci_id_table;
+
+	pci_drv->id_table->device_id = PCI_ANY_ID;
+	pci_drv->id_table->subsystem_device_id = PCI_ANY_ID;
+	pci_drv->id_table->vendor_id = PCI_ANY_ID;
+	pci_drv->id_table->subsystem_vendor_id = PCI_ANY_ID;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, socket_id);
+	if (internals == NULL) {
+		RTE_LOG(ERR, PMD, "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");
+		goto err;
+	}
+
+	pci_dev->numa_node = socket_id;
+	pci_drv->name = driver_name;
+
+	eth_drv->pci_drv = (struct rte_pci_driver)(*pci_drv);
+	eth_dev->driver = eth_drv;
+
+	eth_dev->data->dev_private = internals;
+	eth_dev->data->nb_rx_queues = (uint16_t)1;
+	eth_dev->data->nb_tx_queues = (uint16_t)1;
+
+	eth_dev->data->dev_link.link_status = 0;
+
+	eth_dev->data->mac_addrs = rte_zmalloc_socket(name, ETHER_ADDR_LEN, 0,
+			socket_id);
+
+	eth_dev->data->dev_started = 0;
+	eth_dev->data->promiscuous = 0;
+	eth_dev->data->scattered_rx = 0;
+	eth_dev->data->all_multicast = 0;
+
+	eth_dev->dev_ops = &default_dev_ops;
+	eth_dev->pci_dev = pci_dev;
+
+	eth_dev->rx_pkt_burst = bond_ethdev_rx_burst;
+	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);
+		goto err;
+	}
+
+	internals->current_primary_port = 0;
+	internals->balance_xmit_policy = BALANCE_XMIT_POLICY_LAYER2;
+	internals->user_defined_mac = 0;
+	internals->link_props_set = 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:
+	if (pci_dev)
+		rte_free(pci_dev);
+	if (pci_drv)
+		rte_free(pci_drv);
+	if (pci_id_table)
+		rte_free(pci_id_table);
+	if (eth_drv)
+		rte_free(eth_drv);
+	if (internals)
+		rte_free(internals);
+	return -1;
+}
+
+static inline int
+find_port_id_by_pci_addr(const struct rte_pci_addr *pci_addr)
+{
+	struct rte_pci_addr *eth_pci_addr;
+	unsigned i;
+
+	for (i = 0; i < rte_eth_dev_count(); i++) {
+
+		if (rte_eth_devices[i].pci_dev == NULL)
+			continue;
+
+		eth_pci_addr = &(rte_eth_devices[i].pci_dev->addr);
+
+		if (pci_addr->bus == eth_pci_addr->bus &&
+			pci_addr->devid == eth_pci_addr->devid &&
+			pci_addr->domain == eth_pci_addr->domain &&
+			pci_addr->function == eth_pci_addr->function)
+			return i;
+	}
+	return -1;
+}
+
+static inline int
+find_port_id_by_dev_name(const char *name)
+{
+	unsigned i;
+
+	for (i = 0; i < rte_eth_dev_count(); i++) {
+		if (rte_eth_devices[i].data == NULL)
+			continue;
+
+		if (strcmp(rte_eth_devices[i].data->name, name) == 0)
+			return i;
+	}
+	return -1;
+}
+
+/**
+ * Parses a port identifier string to a port id by pci address, then by name,
+ * and finally port id.
+ */
+static inline int
+parse_port_id(const char *port_str)
+{
+	struct rte_pci_addr dev_addr;
+	int port_id;
+
+	/* try parsing as pci address, physical devices */
+	if (eal_parse_pci_DomBDF(port_str, &dev_addr) == 0) {
+		port_id = find_port_id_by_pci_addr(&dev_addr);
+		if (port_id < 0)
+			return -1;
+	} else {
+		/* try parsing as device name, virtual devices */
+		port_id = find_port_id_by_dev_name(port_str);
+		if (port_id < 0) {
+			char *end;
+			errno = 0;
+
+			/* try parsing as port id */
+			port_id = strtol(port_str, &end, 10);
+			if (*end != 0 || errno != 0)
+				return -1;
+		}
+	}
+
+	if (port_id < 0 || port_id > RTE_MAX_ETHPORTS) {
+		RTE_LOG(ERR, PMD, "Invalid slave port value (%s) specified.\n",
+				port_str);
+		return -1;
+	}
+
+	return port_id;
+}
+static int
+bond_ethdev_parse_slave_port_kvarg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	struct bond_ethdev_slave_ports *slave_ports;
+
+	if (value == NULL || extra_args == NULL)
+		return -1;
+
+	slave_ports = extra_args;
+
+	if (strcmp(key, PMD_BOND_SLAVE_PORT_KVARG) == 0) {
+		int port_id = parse_port_id(value);
+		if (port_id < 0)
+			return -1;
+		else
+			slave_ports->slaves[slave_ports->slave_count++] =
+					(uint8_t)port_id;
+	}
+	return 0;
+}
+
+static int
+bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	uint8_t *mode;
+	char *endptr;
+
+	if (value == NULL || extra_args == NULL)
+		return -1;
+
+	mode = extra_args;
+
+	errno = 0;
+	*mode = strtol(value, &endptr, 10);
+	if (*endptr != 0 || errno != 0)
+		return -1;
+
+	/* validate mode value */
+	switch (*mode) {
+	case BONDING_MODE_ROUND_ROBIN:
+	case BONDING_MODE_ACTIVE_BACKUP:
+	case BONDING_MODE_BALANCE:
+	case BONDING_MODE_BROADCAST:
+		return 0;
+	default:
+		return -1;
+	}
+}
+
+static int
+bond_ethdev_parse_socket_id_kvarg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	int socket_id;
+	char *endptr;
+
+	if (value == NULL || extra_args == NULL)
+		return -1;
+
+	errno = 0;
+	socket_id = (uint8_t)strtol(value, &endptr, 10);
+	if (*endptr != 0 || errno != 0)
+		return -1;
+
+	/* validate mode value */
+	if (socket_id >= 0 && socket_id < number_of_sockets()) {
+		*(uint8_t *)extra_args = (uint8_t)socket_id;
+		return 0;
+	}
+	return -1;
+}
+
+static int
+bond_ethdev_parse_primary_slave_port_id_kvarg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	int primary_slave_port_id;
+
+	if (value == NULL || extra_args == NULL)
+		return -1;
+
+	primary_slave_port_id = parse_port_id(value);
+	if (primary_slave_port_id < 0)
+		return -1;
+
+	*(uint8_t *)extra_args = (uint8_t)primary_slave_port_id;
+
+	return 0;
+}
+
+static int
+bond_ethdev_parse_balance_xmit_policy_kvarg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	uint8_t *xmit_policy;
+
+	if (value == NULL || extra_args == NULL)
+		return -1;
+
+	xmit_policy = extra_args;
+
+	if (strcmp(PMD_BOND_XMIT_POLICY_LAYER2_KVARG, value) == 0)
+		*xmit_policy = BALANCE_XMIT_POLICY_LAYER2;
+	else if (strcmp(PMD_BOND_XMIT_POLICY_LAYER23_KVARG, value) == 0)
+		*xmit_policy = BALANCE_XMIT_POLICY_LAYER23;
+	else if (strcmp(PMD_BOND_XMIT_POLICY_LAYER34_KVARG, value) == 0)
+		*xmit_policy = BALANCE_XMIT_POLICY_LAYER34;
+	else
+		return -1;
+
+	return 0;
+}
+
+static int
+bond_ethdev_parse_bond_mac_addr_kvarg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	if (value == NULL || extra_args == NULL)
+		return -1;
+
+	/* Parse MAC */
+	return cmdline_parse_etheraddr(NULL, value, extra_args);
+}
+
+
+static int
+rte_pmd_bond_init(const char *name, const char *params)
+{
+	struct rte_kvargs *kvlist;
+	uint8_t bonding_mode, socket_id;
+	int  arg_count, port_id;
+
+	RTE_LOG(INFO, EAL, "Initializing pmd_bond for %s\n", name);
+
+	kvlist = rte_kvargs_parse(params, pmd_bond_init_valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	/* Parse link bonding mode */
+	if (rte_kvargs_count(kvlist, PMD_BOND_MODE_KVARG) == 1) {
+		if (rte_kvargs_process(kvlist, PMD_BOND_MODE_KVARG,
+				&bond_ethdev_parse_slave_mode_kvarg, &bonding_mode) != 0) {
+			RTE_LOG(ERR, EAL, "Invalid mode for bonded device %s\n", name);
+			return -1;
+		}
+	} else {
+		RTE_LOG(ERR, EAL,
+				"Mode must be specified only once for bonded device %s\n",
+				name);
+		return -1;
+	}
+
+	/* Parse socket id to create bonding device on */
+	arg_count = rte_kvargs_count(kvlist, PMD_BOND_SOCKET_ID_KVARG);
+	if (arg_count == 1) {
+		if (rte_kvargs_process(kvlist, PMD_BOND_SOCKET_ID_KVARG,
+				&bond_ethdev_parse_socket_id_kvarg, &socket_id) != 0) {
+			RTE_LOG(ERR, EAL,
+					"Invalid socket Id specified for bonded device %s\n",
+					name);
+			return -1;
+		}
+	} else if (arg_count > 1) {
+		RTE_LOG(ERR, EAL,
+				"Socket Id can be specified only once for bonded device %s\n",
+				name);
+		return -1;
+	} else {
+		socket_id = rte_socket_id();
+	}
+
+	/* Create link bonding eth device */
+	port_id = rte_eth_bond_create(name, bonding_mode, socket_id);
+	if (port_id < 0) {
+		RTE_LOG(ERR, EAL,
+				"Failed to create socket %s in mode %u on socket %u.\n",
+				name, bonding_mode, socket_id);
+		return -1;
+	}
+
+	RTE_LOG(INFO, EAL,
+			"Create bonded device %s on port %d in mode %u on socket %u.\n",
+			name, port_id, bonding_mode, socket_id);
+
+	/* Parse MAC address for bonded device */
+	arg_count = rte_kvargs_count(kvlist, PMD_BOND_MAC_ADDR_KVARG);
+	if (arg_count == 1) {
+		struct ether_addr bond_mac;
+
+		if (rte_kvargs_process(kvlist, PMD_BOND_MAC_ADDR_KVARG,
+				&bond_ethdev_parse_bond_mac_addr_kvarg, &bond_mac) < 0) {
+			RTE_LOG(INFO, EAL, "Invalid mac address for bonded device %s\n",
+					name);
+			return -1;
+		}
+
+		/* Set MAC address */
+		if (rte_eth_bond_mac_address_set(port_id, &bond_mac) != 0) {
+			RTE_LOG(ERR, EAL,
+					"Failed to set mac address on bonded device %s\n",
+					name);
+			return -1;
+		}
+	} else if (arg_count > 1) {
+		RTE_LOG(ERR, EAL,
+				"MAC address can be specified only once for bonded device %s\n",
+				name);
+		return -1;
+	}
+
+	/* Parse/set balance mode transmit policy */
+	arg_count = rte_kvargs_count(kvlist, PMD_BOND_XMIT_POLICY_KVARG);
+	if (arg_count == 1) {
+		uint8_t xmit_policy;
+
+		if (rte_kvargs_process(kvlist, PMD_BOND_XMIT_POLICY_KVARG,
+				&bond_ethdev_parse_balance_xmit_policy_kvarg, &xmit_policy) !=
+						0) {
+			RTE_LOG(INFO, EAL,
+					"Invalid xmit policy specified for bonded device %s\n",
+					name);
+			return -1;
+		}
+
+		/* Set balance mode transmit policy*/
+		if (rte_eth_bond_xmit_policy_set(port_id, xmit_policy) != 0) {
+			RTE_LOG(ERR, EAL,
+					"Failed to set balance xmit policy on bonded device %s\n",
+					name);
+			return -1;
+		}
+	} else if (arg_count > 1) {
+		RTE_LOG(ERR, EAL,
+				"Transmit policy can be specified only once for bonded device %s\n",
+				name);
+		return -1;
+	}
+
+	/* Parse/add slave ports to bonded device */
+	if (rte_kvargs_count(kvlist, PMD_BOND_SLAVE_PORT_KVARG) > 0) {
+		struct bond_ethdev_slave_ports slave_ports;
+		unsigned i;
+
+		memset(&slave_ports, 0, sizeof(slave_ports));
+
+		if (rte_kvargs_process(kvlist, PMD_BOND_SLAVE_PORT_KVARG,
+				&bond_ethdev_parse_slave_port_kvarg, &slave_ports) != 0) {
+			RTE_LOG(ERR, EAL,
+					"Failed to parse slave ports for bonded device %s\n",
+					name);
+			return -1;
+		}
+
+		for (i = 0; i < slave_ports.slave_count; i++) {
+			if (rte_eth_bond_slave_add(port_id, slave_ports.slaves[i]) != 0) {
+				RTE_LOG(ERR, EAL,
+						"Failed to add port %d as slave to bonded device %s\n",
+						slave_ports.slaves[i], name);
+			}
+		}
+
+	} else {
+		RTE_LOG(INFO, EAL, "No slaves specified for bonded device %s\n", name);
+		return -1;
+	}
+
+	/* Parse/set primary slave port id*/
+	arg_count = rte_kvargs_count(kvlist, PMD_BOND_PRIMARY_SLAVE_KVARG);
+	if (arg_count == 1) {
+		uint8_t primary_slave_port_id;
+
+		if (rte_kvargs_process(kvlist,
+				PMD_BOND_PRIMARY_SLAVE_KVARG,
+				&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);
+			return -1;
+		}
+
+		/* Set balance mode transmit policy*/
+		if (rte_eth_bond_primary_set(port_id, (uint8_t)primary_slave_port_id)
+				!= 0) {
+			RTE_LOG(ERR, EAL,
+					"Failed to set primary slave port %d on bonded device %s\n",
+					primary_slave_port_id, name);
+			return -1;
+		}
+	} else if (arg_count > 1) {
+		RTE_LOG(INFO, EAL,
+				"Primary slave can be specified only once for bonded device %s\n",
+				name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static struct rte_driver rte_pmd_bond_drv = {
+	.name = PMD_BOND_KVARG,
+	.type = PMD_BDEV,
+	.init = rte_pmd_bond_init,
+};
+
+PMD_REGISTER_DRIVER(rte_pmd_bond_drv);
+
+int
+rte_eth_bond_slave_add(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;
+	struct bond_dev_private *temp_internals;
+	struct rte_eth_link link_props;
+
+	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;
+
+	/*
+	 * 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;
+			}
+		}
+	}
+
+	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);
+
+	if (internals->slave_count < 1) {
+		/* 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));
+
+		/* Make primary slave */
+		internals->primary_port = slave_port_id;
+	} else {
+		/* Check slave link properties are supported if props are set,
+		 * all slaves must be the same */
+		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;
+			}
+		} else {
+			link_properties_set(bonded_eth_dev,
+					&(slave_eth_dev->data->dev_link));
+		}
+	}
+
+	internals->slave_count++;
+
+	/* Update all slave devices MACs*/
+	mac_address_slaves_update(bonded_eth_dev);
+
+	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",
+					slave_port_id);
+			goto err_add;
+		}
+	}
+
+	/* Register link status change callback with bonded device pointer as
+	 * argument*/
+	rte_eth_dev_callback_register(slave_port_id, RTE_ETH_EVENT_INTR_LSC,
+			bond_ethdev_lsc_event_callback, &bonded_eth_dev->data->port_id);
+
+	/* If bonded device is started then we can add the slave to our active
+	 * slave array */
+	if (bonded_eth_dev->data->dev_started) {
+		rte_eth_link_get_nowait(slave_port_id, &link_props);
+
+		 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)
+{
+	struct bond_dev_private *internals;
+	struct slave_conf *slave_conf;
+
+	int i;
+	int pos = -1;
+
+	/* Verify that port id's are valid bonded and slave ports */
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		goto err_del;
+
+	if (valid_slave_port_id(slave_port_id) != 0)
+		goto err_del;
+
+	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;
+
+		/* shift active slaves up active array list */
+		if (pos >= 0 && i < (internals->active_slave_count - 1))
+			internals->active_slaves[i] = internals->active_slaves[i+1];
+	}
+
+	if (pos >= 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;
+
+		/* shift slaves up list */
+		if (pos >= 0 && i < internals->slave_count)
+			internals->slaves[i] = internals->slaves[i+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,
+			bond_ethdev_lsc_event_callback,
+			&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));
+
+	slave_config_clear(internals, &rte_eth_devices[slave_port_id]);
+
+	internals->slave_count--;
+
+	/*  first slave in the active list will be the primary by default,
+	 *  otherwise use first device in list */
+	if (internals->current_primary_port == 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];
+		else
+			internals->primary_port = 0;
+	}
+
+	if (internals->active_slave_count < 1) {
+		/* reset device link properties as no slaves are active */
+		link_properties_reset(&rte_eth_devices[bonded_port_id]);
+
+		/* if no slaves are any longer attached to bonded device and MAC is not
+		 * user defined then clear MAC of bonded device as it will be reset
+		 * when a new slave is added */
+		if (internals->slave_count < 1 && !internals->user_defined_mac)
+			memset(rte_eth_devices[bonded_port_id].data->mac_addrs, 0,
+					sizeof(*(rte_eth_devices[bonded_port_id].data->mac_addrs)));
+	}
+
+	return 0;
+
+err_del:
+	RTE_LOG(ERR, PMD,
+			"Cannot remove slave device (not present in bonded device)\n");
+	return -1;
+
+}
+
+int
+rte_eth_bond_mode_set(uint8_t bonded_port_id, uint8_t mode)
+{
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	return bond_ethdev_mode_set(&rte_eth_devices[bonded_port_id], mode);
+}
+
+
+int
+rte_eth_bond_mode_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->mode;
+}
+
+
+int
+rte_eth_bond_primary_set(uint8_t bonded_port_id, uint8_t slave_port_id)
+{
+	struct bond_dev_private *internals;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (valid_slave_port_id(slave_port_id) != 0)
+		return -1;
+
+	internals =  rte_eth_devices[bonded_port_id].data->dev_private;
+
+	internals->user_defined_primary_port = 1;
+	internals->primary_port = slave_port_id;
+
+	bond_ethdev_primary_set(internals, slave_port_id);
+
+	return 0;
+}
+
+int
+rte_eth_bond_primary_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;
+
+	if (internals->slave_count < 1)
+		return -1;
+
+	return internals->current_primary_port;
+}
+int
+rte_eth_bond_slaves_get(uint8_t bonded_port_id, uint8_t slaves[], uint8_t len)
+{
+	struct bond_dev_private *internals;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (slaves == NULL)
+		return -1;
+
+	internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+	if (internals->slave_count > len)
+		return -1;
+
+	memcpy(slaves, internals->slaves, internals->slave_count);
+
+	return internals->slave_count;
+
+}
+
+int
+rte_eth_bond_active_slaves_get(uint8_t bonded_port_id, uint8_t slaves[],
+		uint8_t len)
+{
+	struct bond_dev_private *internals;
+
+	if (valid_bonded_port_id(bonded_port_id) != 0)
+		return -1;
+
+	if (slaves == NULL)
+		return -1;
+
+	internals = rte_eth_devices[bonded_port_id].data->dev_private;
+
+	if (internals->active_slave_count > len)
+		return -1;
+
+	memcpy(slaves, internals->active_slaves, internals->active_slave_count);
+
+	return internals->active_slave_count;
+}
+
+
+int
+rte_eth_bond_mac_address_set(uint8_t bonded_port_id,
+		struct ether_addr *mac_addr)
+{
+	struct rte_eth_dev *bonded_eth_dev;
+	struct bond_dev_private *internals;
+
+	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;
+
+	/* Set MAC Address of Bonded Device */
+	if (mac_address_set(bonded_eth_dev, mac_addr))
+		return -1;
+
+	internals->user_defined_mac = 1;
+
+	/* Update all slave devices MACs*/
+	if (internals->slave_count > 0)
+		return mac_address_slaves_update(bonded_eth_dev);
+
+	return 0;
+}
+
+
+int
+rte_eth_bond_mac_address_reset(uint8_t bonded_port_id)
+{
+	struct rte_eth_dev *bonded_eth_dev;
+	struct bond_dev_private *internals;
+
+
+	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;
+
+	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)
+			return -1;
+
+		/* Update all slave devices MAC addresses */
+		return mac_address_slaves_update(bonded_eth_dev);
+	}
+	/* No need to update anything as no slaves present */
+	return 0;
+}
+
+int
+rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy)
+{
+	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;
+
+	switch (policy) {
+	case BALANCE_XMIT_POLICY_LAYER2:
+	case BALANCE_XMIT_POLICY_LAYER23:
+	case BALANCE_XMIT_POLICY_LAYER34:
+		internals->balance_xmit_policy = policy;
+		break;
+
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+
+int
+rte_eth_bond_xmit_policy_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->balance_xmit_policy;
+}
+
diff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h
new file mode 100644
index 0000000..7cf9dd8
--- /dev/null
+++ b/lib/librte_pmd_bond/rte_eth_bond.h
@@ -0,0 +1,255 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_BOND_H_
+#define _RTE_ETH_BOND_H_
+
+/**
+ * @file rte_bond.h
+ *
+ * RTE Link Bonding Ethernet Device
+ * Link Bonding for 1GbE and 10GbE ports to allow the aggregation of multiple
+ * (slave) NICs into a single logical interface. The bonded device processes
+ * these interfaces based on the mode of operation specified and supported.
+ * This implementation supports 4 modes of operation round robin, active backup
+ * balance and broadcast. Providing redundant links, fault tolerance and/or
+ * load balancing of network ports
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ether.h>
+
+/* Supported modes of operation of link bonding library  */
+
+#define BONDING_MODE_ROUND_ROBIN		(0)
+/**< Round Robin (Mode 0).
+ * In this mode all transmitted packets will be balanced equally across all
+ * active slaves of the bonded in a round robin fashion. */
+#define BONDING_MODE_ACTIVE_BACKUP		(1)
+/**< Active Backup (Mode 1).
+ * In this mode all packets transmitted will be transmitted on the primary
+ * slave until such point as the primary slave is no longer available and then
+ * transmitted packets will be sent on the next available slaves. The primary
+ * slave can be defined by the user but defaults to the first active slave
+ * available if not specified. */
+#define BONDING_MODE_BALANCE			(2)
+/**< Balance (Mode 2).
+ * In this mode all packets transmitted will be balanced across the available
+ * slaves using one of three available transmit policies - l2, l2+3 or l3+4.
+ * See BALANCE_XMIT_POLICY macros definitions for further details on transmit
+ * policies. */
+#define BONDING_MODE_BROADCAST			(3)
+/**< Broadcast (Mode 3).
+ * In this mode all transmitted packets will be transmitted on all available
+ * active slaves of the bonded. */
+
+/* Balance Mode Transmit Policies */
+#define BALANCE_XMIT_POLICY_LAYER2		(0)
+/**< Layer 2 (Ethernet MAC) */
+#define BALANCE_XMIT_POLICY_LAYER23		(1)
+/**< Layer 2+3 (Ethernet MAC + IP Addresses) transmit load balancing */
+#define BALANCE_XMIT_POLICY_LAYER34		(2)
+/**< Layer 3+4 (IP Addresses + UDP Ports) transmit load balancing */
+
+/**
+ * Create a bonded rte_eth_dev device
+ *
+ * @param name			Name of new link bonding device.
+ * @param mode			Mode to initialize bonding device in.
+ * @param socket_id		Socket Id on which to allocate eth_dev resources.
+ *
+ * @return
+ *	Port Id of created rte_eth_dev on success, negative value otherwise
+ */
+int
+rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id);
+
+/**
+ * Add a rte_eth_dev device as a slave to the bonded device
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ * @param slave_port_id		Port ID of slave device.
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_slave_add(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Remove a slave rte_eth_dev device from the bonded device
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ * @param slave_port_id		Port ID of slave device.
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_slave_remove(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Set link bonding mode of bonded device
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ * @param mode				Bonding mode to set
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mode_set(uint8_t bonded_port_id, uint8_t mode);
+
+/**
+ * Get link bonding mode of bonded device
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ *
+ * @return
+ *	link bonding mode on success, negative value otherwise
+ */
+int
+rte_eth_bond_mode_get(uint8_t bonded_port_id);
+
+/**
+ * Set slave rte_eth_dev as primary slave of bonded device
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ * @param slave_port_id		Port ID of slave device.
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_primary_set(uint8_t bonded_port_id, uint8_t slave_port_id);
+
+/**
+ * Get primary slave of bonded device
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ *
+ * @return
+ *	Port Id of primary slave on success, -1 on failure
+ */
+int
+rte_eth_bond_primary_get(uint8_t bonded_port_id);
+
+/**
+ * Populate an array with list of the slaves port id's of the bonded device
+ *
+ * @param bonded_port_id	Port ID of bonded eth_dev to interrogate
+ * @param slaves			Array to be populated with the current active slaves
+ * @param len				Length of slaves array
+ *
+ * @return
+ *	Number of slaves associated with bonded device on success,
+ *	negative value otherwise
+ */
+int
+rte_eth_bond_slaves_get(uint8_t bonded_port_id, uint8_t slaves[], uint8_t len);
+
+/**
+ * Populate an array with list of the active slaves port id's of the bonded
+ * device.
+ *
+ * @param bonded_port_id	Port ID of bonded eth_dev to interrogate
+ * @param slaves			Array to be populated with the current active slaves
+ * @param len				Length of slaves array
+ *
+ * @return
+ *	Number of active slaves associated with bonded device on success,
+ *	negative value otherwise
+ */
+int
+rte_eth_bond_active_slaves_get(uint8_t bonded_port_id, uint8_t slaves[],
+		uint8_t len);
+
+/**
+ * Set explicit MAC address to use on bonded device and it's slaves.
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ * @param mac_addr			MAC Address to use on bonded device overriding
+ *							slaves MAC addresses
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mac_address_set(uint8_t bonded_port_id,
+		struct ether_addr *mac_addr);
+
+/**
+ * Reset bonded device to use MAC from primary slave on bonded device and it's
+ * slaves.
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ *
+ * @return
+ *	0 on success, negative value otherwise
+ */
+int
+rte_eth_bond_mac_address_reset(uint8_t bonded_port_id);
+
+/**
+ * Set the transmit policy for bonded device to use when it is operating in
+ * balance mode, this parameter is otherwise ignored in other modes of
+ * operation.
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ * @param policy			Balance mode transmission policy.
+ *
+ * @return
+ *	0 on success, negative value otherwise.
+ */
+int
+rte_eth_bond_xmit_policy_set(uint8_t bonded_port_id, uint8_t policy);
+
+/**
+ * Get the transmit policy set on bonded device for balance mode operation
+ *
+ * @param bonded_port_id	Port ID of bonded device.
+ *
+ * @return
+ *	Balance transmit policy on success, negative value otherwise.
+ */
+int
+rte_eth_bond_xmit_policy_get(uint8_t bonded_port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 914c568..66de6a8 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -181,8 +181,13 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_PCAP),y)
 LDLIBS += -lrte_pmd_pcap -lpcap
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
+LDLIBS += -lrte_pmd_bond
 endif
 
+endif
+
+
 LDLIBS += $(EXECENV_LDLIBS)
 
 LDLIBS += --end-group
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v3 2/5] Link Bonding PMD Library (librte_eal/librte_ether link bonding support changes)
  2014-06-13 14:41 ` [dpdk-dev] [PATCH v3 0/5] Link Bonding PMD Library Declan Doherty
  2014-06-13 14:41   ` [dpdk-dev] [PATCH v3 1/5] " Declan Doherty
@ 2014-06-13 14:41   ` Declan Doherty
  2014-06-13 16:08     ` Neil Horman
  2014-06-13 21:59     ` Stephen Hemminger
  2014-06-13 14:42   ` [dpdk-dev] [PATCH v3 3/5] Link Bonding PMD Library (Unit Test Suite) Declan Doherty
                     ` (10 subsequent siblings)
  12 siblings, 2 replies; 127+ messages in thread
From: Declan Doherty @ 2014-06-13 14:41 UTC (permalink / raw)
  To: dev, dev

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 15528 bytes --]

Updating functionality in EAL to support adding link bonding
devices via –vdev option. Link bonding devices will be
initialized after all physical devices have been probed and
initialized.

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 lib/librte_eal/common/eal_common_dev.c      | 66 +++++++++++++++++++++++++++--
 lib/librte_eal/common/eal_common_pci.c      |  6 +++
 lib/librte_eal/common/include/eal_private.h |  7 +++
 lib/librte_eal/common/include/rte_dev.h     |  1 +
 lib/librte_ether/rte_ethdev.c               | 34 +++++++++++++--
 lib/librte_ether/rte_ethdev.h               |  7 ++-
 lib/librte_pmd_pcap/rte_eth_pcap.c          | 22 +++++-----
 lib/librte_pmd_ring/rte_eth_ring.c          | 32 +++++++-------
 lib/librte_pmd_ring/rte_eth_ring.h          |  3 +-
 lib/librte_pmd_xenvirt/rte_eth_xenvirt.c    |  2 +-
 10 files changed, 144 insertions(+), 36 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index eae5656..b50c908 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -75,14 +75,28 @@ rte_eal_dev_init(void)
 
 	/* call the init function for each virtual device */
 	TAILQ_FOREACH(devargs, &devargs_list, next) {
+		uint8_t bdev = 0;
 
 		if (devargs->type != RTE_DEVTYPE_VIRTUAL)
 			continue;
 
 		TAILQ_FOREACH(driver, &dev_driver_list, next) {
-			if (driver->type != PMD_VDEV)
+			/* RTE_DEVTYPE_VIRTUAL can only be a virtual or bonded device*/
+			if (driver->type != PMD_VDEV && driver->type != PMD_BDEV)
 				continue;
 
+			/*
+			 * Bonded devices are not initialize here, we do it later in
+			 * rte_eal_bonded_dev_init() after all physical devices have been
+			 * probed and initialized
+			 */
+			if (driver->type == PMD_BDEV &&
+					!strncmp(driver->name, devargs->virtual.drv_name,
+							strlen(driver->name))) {
+				bdev = 1;
+				break;
+			}
+
 			/* search a driver prefix in virtual device name */
 			if (!strncmp(driver->name, devargs->virtual.drv_name,
 					strlen(driver->name))) {
@@ -92,9 +106,9 @@ rte_eal_dev_init(void)
 			}
 		}
 
-		if (driver == NULL) {
-			rte_panic("no driver found for %s\n",
-				  devargs->virtual.drv_name);
+		if (driver == NULL && !bdev) {
+			rte_panic("no driver found for %s and is not a bonded vdev %d\n",
+				  devargs->virtual.drv_name, bdev);
 		}
 	}
 
@@ -107,3 +121,47 @@ rte_eal_dev_init(void)
 	}
 	return 0;
 }
+
+#ifdef RTE_LIBRTE_PMD_BOND
+int
+rte_eal_bonded_dev_init(void)
+{
+	struct rte_devargs *devargs;
+	struct rte_driver *driver;
+
+	TAILQ_FOREACH(devargs, &devargs_list, next) {
+		int vdev = 0;
+
+		if (devargs->type != RTE_DEVTYPE_VIRTUAL)
+			continue;
+
+		TAILQ_FOREACH(driver, &dev_driver_list, next) {
+			if (driver->type != PMD_VDEV && driver->type != PMD_BDEV)
+				continue;
+
+			/* Virtual devices have already been initialized so we skip them
+			 * here*/
+			if (driver->type == PMD_VDEV &&
+					!strncmp(driver->name, devargs->virtual.drv_name,
+							strlen(driver->name))) {
+				vdev = 1;
+				break;
+			}
+
+			/* search a driver prefix in bonded device name */
+			if (!strncmp(driver->name, devargs->virtual.drv_name,
+					strlen(driver->name))) {
+				driver->init(devargs->virtual.drv_name, devargs->args);
+				break;
+			}
+		}
+
+		if (driver == NULL && !vdev) {
+			rte_panic("no driver found for %s\n",
+					devargs->virtual.drv_name);
+		}
+	}
+	return 0;
+}
+#endif
+
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 4d877ea..9b584f5 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -166,7 +166,13 @@ rte_eal_pci_probe(void)
 				 dev->addr.devid, dev->addr.function);
 	}
 
+#ifdef RTE_LIBRTE_PMD_BOND
+	/* After all physical PCI devices have been probed and initialized then we
+	 * initialize the bonded devices */
+	return rte_eal_bonded_dev_init();
+#else
 	return 0;
+#endif
 }
 
 /* dump one device */
diff --git a/lib/librte_eal/common/include/eal_private.h b/lib/librte_eal/common/include/eal_private.h
index 232fcec..f6081bb 100644
--- a/lib/librte_eal/common/include/eal_private.h
+++ b/lib/librte_eal/common/include/eal_private.h
@@ -203,4 +203,11 @@ int rte_eal_alarm_init(void);
  */
 int rte_eal_dev_init(void);
 
+#ifdef RTE_LIBRTE_PMD_BOND
+/**
+ * Initialize the bonded devices
+ */
+int rte_eal_bonded_dev_init(void);
+#endif
+
 #endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index f7e3a10..f0a780a 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -62,6 +62,7 @@ typedef int (rte_dev_init_t)(const char *name, const char *args);
 enum pmd_type {
 	PMD_VDEV = 0,
 	PMD_PDEV = 1,
+	PMD_BDEV = 2,	/**< Poll Mode Driver Bonded Device*/
 };
 
 /**
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 8011b8b..4c2f1d3 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -64,6 +64,7 @@
 #include <rte_mbuf.h>
 #include <rte_errno.h>
 #include <rte_spinlock.h>
+#include <rte_string_fns.h>
 
 #include "rte_ether.h"
 #include "rte_ethdev.h"
@@ -152,8 +153,21 @@ rte_eth_dev_data_alloc(void)
 				RTE_MAX_ETHPORTS * sizeof(*rte_eth_dev_data));
 }
 
+static int
+rte_eth_dev_name_unique(const char* name)
+{
+	unsigned i;
+
+	for (i = 0; i < nb_ports; i++) {
+		if (strcmp(rte_eth_devices[i].data->name, name) == 0)
+			return -1;
+	}
+
+	return 0;
+}
+
 struct rte_eth_dev *
-rte_eth_dev_allocate(void)
+rte_eth_dev_allocate(const char* name)
 {
 	struct rte_eth_dev *eth_dev;
 
@@ -165,23 +179,37 @@ rte_eth_dev_allocate(void)
 	if (rte_eth_dev_data == NULL)
 		rte_eth_dev_data_alloc();
 
+	if (rte_eth_dev_name_unique(name)) {
+		PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated!\n");
+		return NULL;
+	}
+
 	eth_dev = &rte_eth_devices[nb_ports];
 	eth_dev->data = &rte_eth_dev_data[nb_ports];
+	rte_snprintf(eth_dev->data->name , sizeof(eth_dev->data->name ),
+			"%s", name);
 	eth_dev->data->port_id = nb_ports++;
 	return eth_dev;
 }
 
 static int
 rte_eth_dev_init(struct rte_pci_driver *pci_drv,
-		 struct rte_pci_device *pci_dev)
+		struct rte_pci_device *pci_dev)
 {
 	struct eth_driver    *eth_drv;
 	struct rte_eth_dev *eth_dev;
+	char ethdev_name[RTE_ETH_NAME_MAX_LEN];
+
 	int diag;
 
 	eth_drv = (struct eth_driver *)pci_drv;
 
-	eth_dev = rte_eth_dev_allocate();
+	/* Create unique ethdev name by concatenating drive name and number of
+	 * ports */
+	rte_snprintf(ethdev_name, RTE_ETH_NAME_MAX_LEN, "%d:%d.%d",
+			pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function);
+
+	eth_dev = rte_eth_dev_allocate(ethdev_name);
 	if (eth_dev == NULL)
 		return -ENOMEM;
 
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 67eda50..27ed0ab 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1233,6 +1233,8 @@ struct rte_eth_dev_sriov {
 };
 #define RTE_ETH_DEV_SRIOV(dev)         ((dev)->data->sriov)
 
+#define RTE_ETH_NAME_MAX_LEN (32)
+
 /**
  * @internal
  * The data part, with no function pointers, associated with each ethernet device.
@@ -1241,6 +1243,8 @@ struct rte_eth_dev_sriov {
  * processes in a multi-process configuration.
  */
 struct rte_eth_dev_data {
+	char name[RTE_ETH_NAME_MAX_LEN]; /**< Unique identifier name */
+
 	void **rx_queues; /**< Array of pointers to RX queues. */
 	void **tx_queues; /**< Array of pointers to TX queues. */
 	uint16_t nb_rx_queues; /**< Number of RX queues. */
@@ -1293,10 +1297,11 @@ extern uint8_t rte_eth_dev_count(void);
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
  * to that slot for the driver to use.
  *
+ * @param	name	Unique identifier name for each Ethernet device
  * @return
  *   - Slot in the rte_dev_devices array for a new device;
  */
-struct rte_eth_dev *rte_eth_dev_allocate(void);
+struct rte_eth_dev *rte_eth_dev_allocate(const char *name);
 
 struct eth_driver;
 /**
diff --git a/lib/librte_pmd_pcap/rte_eth_pcap.c b/lib/librte_pmd_pcap/rte_eth_pcap.c
index b3dbbda..cd6c0e1 100644
--- a/lib/librte_pmd_pcap/rte_eth_pcap.c
+++ b/lib/librte_pmd_pcap/rte_eth_pcap.c
@@ -534,7 +534,7 @@ open_tx_iface(const char *key __rte_unused, const char *value, void *extra_args)
 
 
 static int
-rte_pmd_init_internals(const unsigned nb_rx_queues,
+rte_pmd_init_internals(const char* name, const unsigned nb_rx_queues,
 		const unsigned nb_tx_queues,
 		const unsigned numa_node,
 		struct pmd_internals **internals,
@@ -558,20 +558,20 @@ rte_pmd_init_internals(const unsigned nb_rx_queues,
 	/* now do all data allocation - for eth_dev structure, dummy pci driver
 	 * and internal (private) data
 	 */
-	data = rte_zmalloc_socket(NULL, sizeof(*data), 0, numa_node);
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
 	if (data == NULL)
 		goto error;
 
-	pci_dev = rte_zmalloc_socket(NULL, sizeof(*pci_dev), 0, numa_node);
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
 	if (pci_dev == NULL)
 		goto error;
 
-	*internals = rte_zmalloc_socket(NULL, sizeof(**internals), 0, numa_node);
+	*internals = rte_zmalloc_socket(name, sizeof(**internals), 0, numa_node);
 	if (*internals == NULL)
 		goto error;
 
 	/* reserve an ethdev entry */
-	*eth_dev = rte_eth_dev_allocate();
+	*eth_dev = rte_eth_dev_allocate(name);
 	if (*eth_dev == NULL)
 		goto error;
 
@@ -617,7 +617,7 @@ rte_pmd_init_internals(const unsigned nb_rx_queues,
 }
 
 static int
-rte_eth_from_pcaps_n_dumpers(pcap_t * const rx_queues[],
+rte_eth_from_pcaps_n_dumpers(const char *name, pcap_t * const rx_queues[],
 		const unsigned nb_rx_queues,
 		pcap_dumper_t * const tx_queues[],
 		const unsigned nb_tx_queues,
@@ -634,7 +634,7 @@ rte_eth_from_pcaps_n_dumpers(pcap_t * const rx_queues[],
 	if (tx_queues == NULL && nb_tx_queues > 0)
 		return -1;
 
-	if (rte_pmd_init_internals(nb_rx_queues, nb_tx_queues, numa_node,
+	if (rte_pmd_init_internals(name, nb_rx_queues, nb_tx_queues, numa_node,
 			&internals, &eth_dev, kvlist) < 0)
 		return -1;
 
@@ -652,7 +652,7 @@ rte_eth_from_pcaps_n_dumpers(pcap_t * const rx_queues[],
 }
 
 static int
-rte_eth_from_pcaps(pcap_t * const rx_queues[],
+rte_eth_from_pcaps(const char *name, pcap_t * const rx_queues[],
 		const unsigned nb_rx_queues,
 		pcap_t * const tx_queues[],
 		const unsigned nb_tx_queues,
@@ -669,7 +669,7 @@ rte_eth_from_pcaps(pcap_t * const rx_queues[],
 	if (tx_queues == NULL && nb_tx_queues > 0)
 		return -1;
 
-	if (rte_pmd_init_internals(nb_rx_queues, nb_tx_queues, numa_node,
+	if (rte_pmd_init_internals(name, nb_rx_queues, nb_tx_queues, numa_node,
 			&internals, &eth_dev, kvlist) < 0)
 		return -1;
 
@@ -760,10 +760,10 @@ rte_pmd_pcap_devinit(const char *name, const char *params)
 		return -1;
 
 	if (using_dumpers)
-		return rte_eth_from_pcaps_n_dumpers(pcaps.pcaps, pcaps.num_of_rx,
+		return rte_eth_from_pcaps_n_dumpers(name, pcaps.pcaps, pcaps.num_of_rx,
 				dumpers.dumpers, dumpers.num_of_tx, numa_node, kvlist);
 
-	return rte_eth_from_pcaps(pcaps.pcaps, pcaps.num_of_rx, dumpers.pcaps,
+	return rte_eth_from_pcaps(name, pcaps.pcaps, pcaps.num_of_rx, dumpers.pcaps,
 			dumpers.num_of_tx, numa_node, kvlist);
 
 }
diff --git a/lib/librte_pmd_ring/rte_eth_ring.c b/lib/librte_pmd_ring/rte_eth_ring.c
index 10d4e24..e6779c4 100644
--- a/lib/librte_pmd_ring/rte_eth_ring.c
+++ b/lib/librte_pmd_ring/rte_eth_ring.c
@@ -219,7 +219,7 @@ static struct eth_dev_ops ops = {
 };
 
 int
-rte_eth_from_rings(struct rte_ring *const rx_queues[],
+rte_eth_from_rings(const char* name, struct rte_ring *const rx_queues[],
 		const unsigned nb_rx_queues,
 		struct rte_ring *const tx_queues[],
 		const unsigned nb_tx_queues,
@@ -243,20 +243,20 @@ rte_eth_from_rings(struct rte_ring *const rx_queues[],
 	/* now do all data allocation - for eth_dev structure, dummy pci driver
 	 * and internal (private) data
 	 */
-	data = rte_zmalloc_socket(NULL, sizeof(*data), 0, numa_node);
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
 	if (data == NULL)
 		goto error;
 
-	pci_dev = rte_zmalloc_socket(NULL, sizeof(*pci_dev), 0, numa_node);
+	pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
 	if (pci_dev == NULL)
 		goto error;
 
-	internals = rte_zmalloc_socket(NULL, sizeof(*internals), 0, numa_node);
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
 	if (internals == NULL)
 		goto error;
 
 	/* reserve an ethdev entry */
-	eth_dev = rte_eth_dev_allocate();
+	eth_dev = rte_eth_dev_allocate(name);
 	if (eth_dev == NULL)
 		goto error;
 
@@ -335,7 +335,7 @@ eth_dev_ring_create(const char *name, const unsigned numa_node,
 			return -1;
 	}
 
-	if (rte_eth_from_rings(rxtx, num_rings, rxtx, num_rings, numa_node))
+	if (rte_eth_from_rings(name, rxtx, num_rings, rxtx, num_rings, numa_node))
 		return -1;
 
 	return 0;
@@ -352,29 +352,31 @@ eth_dev_ring_pair_create(const char *name, const unsigned numa_node,
 	struct rte_ring *rx[RTE_PMD_RING_MAX_RX_RINGS];
 	struct rte_ring *tx[RTE_PMD_RING_MAX_TX_RINGS];
 	unsigned i;
-	char rng_name[RTE_RING_NAMESIZE];
+	char rx_rng_name[RTE_RING_NAMESIZE];
+	char tx_rng_name[RTE_RING_NAMESIZE];
 	unsigned num_rings = RTE_MIN(RTE_PMD_RING_MAX_RX_RINGS,
 			RTE_PMD_RING_MAX_TX_RINGS);
 
 	for (i = 0; i < num_rings; i++) {
-		rte_snprintf(rng_name, sizeof(rng_name), "ETH_RX%u_%s", i, name);
+		rte_snprintf(rx_rng_name, sizeof(rx_rng_name), "ETH_RX%u_%s", i, name);
 		rx[i] = (action == DEV_CREATE) ?
-				rte_ring_create(rng_name, 1024, numa_node,
+				rte_ring_create(rx_rng_name, 1024, numa_node,
 						RING_F_SP_ENQ|RING_F_SC_DEQ) :
-				rte_ring_lookup(rng_name);
+				rte_ring_lookup(rx_rng_name);
 		if (rx[i] == NULL)
 			return -1;
-		rte_snprintf(rng_name, sizeof(rng_name), "ETH_TX%u_%s", i, name);
+		rte_snprintf(tx_rng_name, sizeof(tx_rng_name), "ETH_TX%u_%s", i, name);
 		tx[i] = (action == DEV_CREATE) ?
-				rte_ring_create(rng_name, 1024, numa_node,
+				rte_ring_create(tx_rng_name, 1024, numa_node,
 						RING_F_SP_ENQ|RING_F_SC_DEQ):
-				rte_ring_lookup(rng_name);
+				rte_ring_lookup(tx_rng_name);
 		if (tx[i] == NULL)
 			return -1;
 	}
 
-	if (rte_eth_from_rings(rx, num_rings, tx, num_rings, numa_node) ||
-			rte_eth_from_rings(tx, num_rings, rx, num_rings, numa_node) )
+	if (rte_eth_from_rings(rx_rng_name, rx, num_rings, tx, num_rings,
+			numa_node) || rte_eth_from_rings(tx_rng_name, tx, num_rings, rx,
+					num_rings, numa_node) )
 		return -1;
 
 	return 0;
diff --git a/lib/librte_pmd_ring/rte_eth_ring.h b/lib/librte_pmd_ring/rte_eth_ring.h
index ef29344..e6ae19e 100644
--- a/lib/librte_pmd_ring/rte_eth_ring.h
+++ b/lib/librte_pmd_ring/rte_eth_ring.h
@@ -40,7 +40,8 @@ extern "C" {
 
 #include <rte_ring.h>
 
-int rte_eth_from_rings(struct rte_ring * const rx_queues[],
+int rte_eth_from_rings(const char *name,
+		struct rte_ring * const rx_queues[],
 		const unsigned nb_rx_queues,
 		struct rte_ring *const tx_queues[],
 		const unsigned nb_tx_queues,
diff --git a/lib/librte_pmd_xenvirt/rte_eth_xenvirt.c b/lib/librte_pmd_xenvirt/rte_eth_xenvirt.c
index 7c4d3fe..a0b4bdd 100644
--- a/lib/librte_pmd_xenvirt/rte_eth_xenvirt.c
+++ b/lib/librte_pmd_xenvirt/rte_eth_xenvirt.c
@@ -647,7 +647,7 @@ eth_dev_xenvirt_create(const char *name, const char *params,
 		goto err;
 
 	/* reserve an ethdev entry */
-	eth_dev = rte_eth_dev_allocate();
+	eth_dev = rte_eth_dev_allocate(name);
 	if (eth_dev == NULL)
 		goto err;
 
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 127+ messages in thread

* [dpdk-dev] [PATCH v3 3/5] Link Bonding PMD Library (Unit Test Suite)
  2014-06-13 14:41 ` [dpdk-dev] [PATCH v3 0/5] Link Bonding PMD Library Declan Doherty
  2014-06-13 14:41   ` [dpdk-dev] [PATCH v3 1/5] " Declan Doherty
  2014-06-13 14:41   ` [dpdk-dev] [PATCH v3 2/5] Link Bonding PMD Library (librte_eal/librte_ether link bonding support changes) Declan Doherty
@ 2014-06-13 14:42   ` Declan Doherty
  2014-06-13 14:42   ` [dpdk-dev] [PATCH v3 4/5] Link Bonding PMD Library (testpmd link bonding API support) Declan Doherty
                     ` (9 subsequent siblings)
  12 siblings, 0 replies; 127+ messages in thread
From: Declan Doherty @ 2014-06-13 14:42 UTC (permalink / raw)
  To: dev, dev

Link bonding unit tests, including:
 - code to generate packet bursts for testing rx and tx
   functionality of bonded device
 - virtual/stubbed out ethdev for use as slave ethdev in testing


Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 app/test/Makefile                 |    4 +-
 app/test/commands.c               |    7 +
 app/test/packet_burst_generator.c |  288 +++
 app/test/packet_burst_generator.h |   78 +
 app/test/test.h                   |    1 +
 app/test/test_link_bonding.c      | 3958 +++++++++++++++++++++++++++++++++++++
 app/test/virtual_pmd.c            |  574 ++++++
 app/test/virtual_pmd.h            |   74 +
 8 files changed, 4983 insertions(+), 1 deletion(-)
 create mode 100644 app/test/packet_burst_generator.c
 create mode 100644 app/test/packet_burst_generator.h
 create mode 100644 app/test/test_link_bonding.c
 create mode 100644 app/test/virtual_pmd.c
 create mode 100644 app/test/virtual_pmd.h

diff --git a/app/test/Makefile b/app/test/Makefile
index 3b050c3..02eff0f 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -96,7 +96,9 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_ivshmem.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_distributor.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_distributor_perf.c
 SRCS-$(CONFIG_RTE_APP_TEST) += test_devargs.c
-
+SRCS-$(CONFIG_RTE_APP_TEST) += virtual_pmd.c
+SRCS-$(CONFIG_RTE_APP_TEST) += packet_burst_generator.c
+SRCS-$(CONFIG_RTE_APP_TEST) += test_link_bonding.c
 ifeq ($(CONFIG_RTE_APP_TEST),y)
 SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring.c
diff --git a/app/test/commands.c b/app/test/commands.c
index 016410d..c31389d 100644
--- a/app/test/commands.c
+++ b/app/test/commands.c
@@ -157,6 +157,10 @@ static void cmd_autotest_parsed(void *parsed_result,
 		ret = test_timer();
 	if (!strcmp(res->autotest, "timer_perf_autotest"))
 		ret = test_timer_perf();
+#ifdef RTE_LIBRTE_PMD_BOND
+	if (!strcmp(res->autotest, "link_bonding_autotest"))
+		ret = test_link_bonding();
+#endif
 	if (!strcmp(res->autotest, "mempool_autotest"))
 		ret = test_mempool();
 	if (!strcmp(res->autotest, "mempool_perf_autotest"))
@@ -225,6 +229,9 @@ cmdline_parse_token_string_t cmd_autotest_autotest =
 			"alarm_autotest#interrupt_autotest#"
 			"version_autotest#eal_fs_autotest#"
 			"cmdline_autotest#func_reentrancy_autotest#"
+#ifdef RTE_LIBRTE_PMD_BOND
+			"link_bonding_autotest#"
+#endif
 			"mempool_perf_autotest#hash_perf_autotest#"
 			"memcpy_perf_autotest#ring_perf_autotest#"
 			"red_autotest#meter_autotest#sched_autotest#"
diff --git a/app/test/packet_burst_generator.c b/app/test/packet_burst_generator.c
new file mode 100644
index 0000000..38db383
--- /dev/null
+++ b/app/test/packet_burst_generator.c
@@ -0,0 +1,288 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_byteorder.h>
+#include <rte_mbuf.h>
+
+#include "packet_burst_generator.h"
+
+#define UDP_SRC_PORT 1024
+#define UDP_DST_PORT 1024
+
+
+#define IP_DEFTTL  64   /* from RFC 1340. */
+#define IP_VERSION 0x40
+#define IP_HDRLEN  0x05 /* default IP header length == five 32-bits words. */
+#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
+
+static void
+copy_buf_to_pkt_segs(void *buf, unsigned len, struct rte_mbuf *pkt,
+		unsigned offset)
+{
+	struct rte_mbuf *seg;
+	void *seg_buf;
+	unsigned copy_len;
+
+	seg = pkt;
+	while (offset >= seg->pkt.data_len) {
+		offset -= seg->pkt.data_len;
+		seg = seg->pkt.next;
+	}
+	copy_len = seg->pkt.data_len - offset;
+	seg_buf = ((char *) seg->pkt.data + offset);
+	while (len > copy_len) {
+		rte_memcpy(seg_buf, buf, (size_t) copy_len);
+		len -= copy_len;
+		buf = ((char *) buf + copy_len);
+		seg = seg->pkt.next;
+		seg_buf = seg->pkt.data;
+	}
+	rte_memcpy(seg_buf, buf, (size_t) len);
+}
+
+static inline void
+copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
+{
+	if (offset + len <= pkt->pkt.data_len) {
+		rte_memcpy(((char *) pkt->pkt.data + offset), buf, (size_t) len);
+		return;
+	}
+	copy_buf_to_pkt_segs(buf, len, pkt, offset);
+}
+
+
+void
+initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint8_t vlan_enabled, uint16_t van_id)
+{
+	ether_addr_copy(dst_mac, &eth_hdr->d_addr);
+	ether_addr_copy(src_mac, &eth_hdr->s_addr);
+
+	if (vlan_enabled) {
+		struct vlan_hdr *vhdr = (struct vlan_hdr *)((uint8_t *)eth_hdr +
+				sizeof(struct ether_hdr));
+
+		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+
+		vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		vhdr->vlan_tci = van_id;
+	} else {
+		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	}
+
+}
+
+uint16_t
+initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
+		uint16_t dst_port, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct udp_hdr));
+
+	udp_hdr->src_port = rte_cpu_to_be_16(src_port);
+	udp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
+	udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len);
+	udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
+
+	return pkt_len;
+}
+
+
+uint16_t
+initialize_ipv6_header(struct ipv6_hdr *ip_hdr, uint8_t *src_addr,
+		uint8_t *dst_addr, uint16_t pkt_data_len)
+{
+	ip_hdr->vtc_flow = 0;
+	ip_hdr->payload_len = pkt_data_len;
+	ip_hdr->proto = IPPROTO_UDP;
+	ip_hdr->hop_limits = IP_DEFTTL;
+
+	rte_memcpy(ip_hdr->src_addr, src_addr, sizeof(ip_hdr->src_addr));
+	rte_memcpy(ip_hdr->dst_addr, dst_addr, sizeof(ip_hdr->dst_addr));
+
+	return (uint16_t) (pkt_data_len + sizeof(struct ipv6_hdr));
+}
+
+uint16_t
+initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+		uint32_t dst_addr, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+	uint16_t *ptr16;
+	uint32_t ip_cksum;
+
+	/*
+	 * Initialize IP header.
+	 */
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct ipv4_hdr));
+
+	ip_hdr->version_ihl   = IP_VHL_DEF;
+	ip_hdr->type_of_service   = 0;
+	ip_hdr->fragment_offset = 0;
+	ip_hdr->time_to_live   = IP_DEFTTL;
+	ip_hdr->next_proto_id = IPPROTO_UDP;
+	ip_hdr->packet_id = 0;
+	ip_hdr->total_length   = rte_cpu_to_be_16(pkt_len);
+	ip_hdr->src_addr = rte_cpu_to_be_32(src_addr);
+	ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr);
+
+	/*
+	 * Compute IP header checksum.
+	 */
+	ptr16 = (uint16_t *)ip_hdr;
+	ip_cksum = 0;
+	ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
+	ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
+	ip_cksum += ptr16[4];
+	ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
+	ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
+
+	/*
+	 * Reduce 32 bit checksum to 16 bits and complement it.
+	 */
+	ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
+		(ip_cksum & 0x0000FFFF);
+	ip_cksum %= 65536;
+	ip_cksum = (~ip_cksum) & 0x0000FFFF;
+	if (ip_cksum == 0)
+		ip_cksum = 0xFFFF;
+	ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
+
+	return pkt_len;
+}
+
+
+
+/*
+ * The maximum number of segments per packet is used when creating
+ * scattered transmit packets composed of a list of mbufs.
+ */
+#define RTE_MAX_SEGS_PER_PKT 255 /**< pkt.nb_segs is a 8-bit unsigned char. */
+
+#define TXONLY_DEF_PACKET_LEN 64
+#define TXONLY_DEF_PACKET_LEN_128 128
+
+uint16_t tx_pkt_length = TXONLY_DEF_PACKET_LEN;
+uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT] = {
+		TXONLY_DEF_PACKET_LEN_128,
+};
+
+uint8_t  tx_pkt_nb_segs = 1;
+
+int
+generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
+		struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr,
+		uint8_t ipv4, struct udp_hdr *udp_hdr, int nb_pkt_per_burst)
+{
+	int i, nb_pkt = 0;
+	size_t eth_hdr_size;
+
+	struct rte_mbuf *pkt_seg;
+	struct rte_mbuf *pkt;
+
+	for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+		pkt = rte_pktmbuf_alloc(mp);
+		if (pkt == NULL) {
+nomore_mbuf:
+			if (nb_pkt == 0)
+				return -1;
+			break;
+		}
+
+		pkt->pkt.data_len = tx_pkt_seg_lengths[0];
+		pkt_seg = pkt;
+		for (i = 1; i < tx_pkt_nb_segs; i++) {
+			pkt_seg->pkt.next = rte_pktmbuf_alloc(mp);
+			if (pkt_seg->pkt.next == NULL) {
+				pkt->pkt.nb_segs = i;
+				rte_pktmbuf_free(pkt);
+				goto nomore_mbuf;
+			}
+			pkt_seg = pkt_seg->pkt.next;
+			pkt_seg->pkt.data_len = tx_pkt_seg_lengths[i];
+		}
+		pkt_seg->pkt.next = NULL; /* Last segment of packet. */
+
+		/*
+		 * Copy headers in first packet segment(s).
+		 */
+		if (vlan_enabled)
+			eth_hdr_size = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr);
+		else
+			eth_hdr_size = sizeof(struct ether_hdr);
+
+		copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0);
+
+		if (ipv4) {
+			copy_buf_to_pkt(ip_hdr, sizeof(struct ipv4_hdr), pkt, eth_hdr_size);
+			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size +
+					sizeof(struct ipv4_hdr));
+		} else {
+			copy_buf_to_pkt(ip_hdr, sizeof(struct ipv6_hdr), pkt, eth_hdr_size);
+			copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size +
+					sizeof(struct ipv6_hdr));
+		}
+
+		/*
+		 * Complete first mbuf of packet and append it to the
+		 * burst of packets to be transmitted.
+		 */
+		pkt->pkt.nb_segs = tx_pkt_nb_segs;
+		pkt->pkt.pkt_len = tx_pkt_length;
+		pkt->pkt.vlan_macip.f.l2_len = eth_hdr_size;
+
+		if (ipv4) {
+			pkt->pkt.vlan_macip.f.vlan_tci  = ETHER_TYPE_IPv4;
+			pkt->pkt.vlan_macip.f.l3_len = sizeof(struct ipv4_hdr);
+
+			if (vlan_enabled)
+				pkt->ol_flags = PKT_RX_IPV4_HDR | PKT_RX_VLAN_PKT;
+			else
+				pkt->ol_flags = PKT_RX_IPV4_HDR;
+		} else {
+			pkt->pkt.vlan_macip.f.vlan_tci  = ETHER_TYPE_IPv6;
+			pkt->pkt.vlan_macip.f.l3_len = sizeof(struct ipv6_hdr);
+
+			if (vlan_enabled)
+				pkt->ol_flags = PKT_RX_IPV6_HDR | PKT_RX_VLAN_PKT;
+			else
+				pkt->ol_flags = PKT_RX_IPV6_HDR;
+		}
+
+		pkts_burst[nb_pkt] = pkt;
+	}
+
+	return nb_pkt;
+}
+
diff --git a/app/test/packet_burst_generator.h b/app/test/packet_burst_generator.h
new file mode 100644
index 0000000..5b3cd6c
--- /dev/null
+++ b/app/test/packet_burst_generator.h
@@ -0,0 +1,78 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PACKET_BURST_GENERATOR_H_
+#define PACKET_BURST_GENERATOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+
+
+#define IPV4_ADDR(a, b, c, d)(((a & 0xff) << 24) | ((b & 0xff) << 16) | \
+		((c & 0xff) << 8) | (d & 0xff))
+
+
+void
+initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint8_t vlan_enabled, uint16_t van_id);
+
+uint16_t
+initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
+		uint16_t dst_port, uint16_t pkt_data_len);
+
+
+uint16_t
+initialize_ipv6_header(struct ipv6_hdr *ip_hdr, uint8_t *src_addr,
+		uint8_t *dst_addr, uint16_t pkt_data_len);
+
+uint16_t
+initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+		uint32_t dst_addr, uint16_t pkt_data_len);
+
+int
+generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
+		struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr,
+		uint8_t ipv4, struct udp_hdr *udp_hdr, int nb_pkt_per_burst);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* PACKET_BURST_GENERATOR_H_ */
diff --git a/app/test/test.h b/app/test/test.h
index f992ceb..574841b 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -96,6 +96,7 @@ int test_distributor(void);
 int test_distributor_perf(void);
 int test_kvargs(void);
 int test_devargs(void);
+int test_link_bonding(void);
 
 int test_pci_run;
 
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
new file mode 100644
index 0000000..f76a6d5
--- /dev/null
+++ b/app/test/test_link_bonding.c
@@ -0,0 +1,3958 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_memory.h>
+#include <rte_string_fns.h>
+#include <rte_eth_bond.h>
+
+#include "virtual_pmd.h"
+#include "packet_burst_generator.h"
+
+#include "test.h"
+
+#define TEST_MAX_NUMBER_OF_PORTS (16)
+
+#define RX_RING_SIZE 128
+#define RX_FREE_THRESH 32
+#define RX_PTHRESH 8
+#define RX_HTHRESH 8
+#define RX_WTHRESH 0
+
+#define TX_RING_SIZE 512
+#define TX_FREE_THRESH 32
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+#define TX_RSBIT_THRESH 32
+#define TX_Q_FLAGS (ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOVLANOFFL |\
+	ETH_TXQ_FLAGS_NOXSUMSCTP | ETH_TXQ_FLAGS_NOXSUMUDP | \
+	ETH_TXQ_FLAGS_NOXSUMTCP)
+
+#define MBUF_PAYLOAD_SIZE	(2048)
+#define MBUF_SIZE (MBUF_PAYLOAD_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define MBUF_CACHE_SIZE (250)
+#define BURST_SIZE (32)
+
+#define DEFAULT_MBUF_DATA_SIZE	(2048)
+#define RTE_TEST_RX_DESC_MAX	(2048)
+#define RTE_TEST_TX_DESC_MAX	(2048)
+#define MAX_PKT_BURST			(512)
+#define DEF_PKT_BURST			(16)
+
+#define BONDED_DEV_NAME			("unit_test_bonded_device")
+
+#define INVALID_SOCKET_ID		(-1)
+#define INVALID_PORT_ID			(-1)
+#define INVALID_BONDING_MODE	(-1)
+
+
+uint8_t slave_mac[] = {0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 };
+uint8_t bonded_mac[] = {0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
+
+struct link_bonding_unittest_params {
+	int8_t bonded_port_id;
+	int8_t slave_port_ids[TEST_MAX_NUMBER_OF_PORTS];
+	uint8_t bonded_slave_count;
+	uint8_t bonding_mode;
+
+	uint16_t nb_rx_q;
+	uint16_t nb_tx_q;
+
+	struct rte_mempool *mbuf_pool;
+
+	struct ether_addr *default_slave_mac;
+	struct ether_addr *default_bonded_mac;
+
+	/* Packet Headers */
+	struct ether_hdr *pkt_eth_hdr;
+	struct ipv4_hdr *pkt_ipv4_hdr;
+	struct ipv6_hdr *pkt_ipv6_hdr;
+	struct udp_hdr *pkt_udp_hdr;
+
+};
+
+static struct ipv4_hdr pkt_ipv4_hdr;
+static struct ipv6_hdr pkt_ipv6_hdr;
+static struct udp_hdr pkt_udp_hdr;
+
+static struct link_bonding_unittest_params default_params  = {
+	.bonded_port_id = -1,
+	.slave_port_ids = { 0 },
+	.bonded_slave_count = 0,
+	.bonding_mode = BONDING_MODE_ROUND_ROBIN,
+
+	.nb_rx_q = 1,
+	.nb_tx_q = 1,
+
+	.mbuf_pool = NULL,
+
+	.default_slave_mac = (struct ether_addr *)slave_mac,
+	.default_bonded_mac = (struct ether_addr *)bonded_mac,
+
+	.pkt_eth_hdr = NULL,
+	.pkt_ipv4_hdr = &pkt_ipv4_hdr,
+	.pkt_ipv6_hdr = &pkt_ipv6_hdr,
+	.pkt_udp_hdr = &pkt_udp_hdr
+
+};
+
+static struct link_bonding_unittest_params *test_params = &default_params;
+
+static uint8_t src_mac[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
+static uint8_t dst_mac_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
+static uint8_t dst_mac_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAB };
+
+static uint32_t src_addr = IPV4_ADDR(192, 168, 1, 98);
+static uint32_t dst_addr_0 = IPV4_ADDR(192, 168, 1, 98);
+static uint32_t dst_addr_1 = IPV4_ADDR(193, 166, 10, 97);
+
+static uint8_t src_ipv6_addr[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA  };
+static uint8_t dst_ipv6_addr_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA,  0xFF, 0xAA , 0xFF, 0xAA, 0xFF, 0xAA  };
+static uint8_t dst_ipv6_addr_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF,
+		0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA , 0xFF, 0xAB  };
+
+static uint16_t src_port = 1024;
+static uint16_t dst_port_0 = 1024;
+static uint16_t dst_port_1 = 2024;
+
+static uint16_t vlan_id = 0x100;
+
+struct rte_eth_rxmode rx_mode = {
+	.max_rx_pkt_len = ETHER_MAX_LEN, /**< Default maximum frame length. */
+	.split_hdr_size = 0,
+	.header_split   = 0, /**< Header Split disabled. */
+	.hw_ip_checksum = 0, /**< IP checksum offload disabled. */
+	.hw_vlan_filter = 1, /**< VLAN filtering enabled. */
+	.hw_vlan_strip  = 1, /**< VLAN strip enabled. */
+	.hw_vlan_extend = 0, /**< Extended VLAN disabled. */
+	.jumbo_frame    = 0, /**< Jumbo Frame Support disabled. */
+	.hw_strip_crc   = 0, /**< CRC stripping by hardware disabled. */
+};
+
+struct rte_fdir_conf fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.flexbytes_offset = 0x6,
+	.drop_queue = 127,
+};
+
+static struct rte_eth_conf default_pmd_conf = {
+	.rxmode = {
+		.mq_mode = ETH_MQ_RX_NONE,
+		.max_rx_pkt_len = ETHER_MAX_LEN,
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload enabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.lpbk_mode = 0,
+};
+
+static const struct rte_eth_rxconf rx_conf_default = {
+	.rx_thresh = {
+		.pthresh = RX_PTHRESH,
+		.hthresh = RX_HTHRESH,
+		.wthresh = RX_WTHRESH,
+	},
+	.rx_free_thresh = RX_FREE_THRESH,
+	.rx_drop_en = 0,
+};
+
+static struct rte_eth_txconf tx_conf_default = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = TX_FREE_THRESH,
+	.tx_rs_thresh = TX_RSBIT_THRESH,
+	.txq_flags = TX_Q_FLAGS
+
+};
+
+static int
+configure_ethdev(uint8_t port_id, uint8_t start)
+{
+	int q_id;
+
+	if (rte_eth_dev_configure(port_id, test_params->nb_rx_q,
+			test_params->nb_tx_q, &default_pmd_conf) != 0) {
+		goto error;
+	}
+
+	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,
+				rte_eth_dev_socket_id(port_id), &rx_conf_default,
+				test_params->mbuf_pool) < 0) {
+			goto error;
+		}
+	}
+
+	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;
+		}
+	}
+
+	if (start) {
+		if (rte_eth_dev_start(port_id) < 0) {
+			printf("Failed to start device (%d).\n", port_id);
+			goto error;
+		}
+	}
+	return 0;
+
+error:
+	printf("Failed to configure ethdev %d", port_id);
+	return -1;
+}
+
+
+static int
+test_setup(void)
+{
+	int i, retval, nb_mbuf_per_pool;
+	struct ether_addr *mac_addr = (struct ether_addr *)slave_mac;
+
+	/* Allocate ethernet packet header with space for VLAN header */
+	test_params->pkt_eth_hdr = malloc(sizeof(struct ether_hdr) +
+			sizeof(struct vlan_hdr));
+	if (test_params->pkt_eth_hdr == NULL) {
+		printf("ethernet header struct allocation failed!\n");
+		return -1;
+	}
+
+
+	nb_mbuf_per_pool = RTE_TEST_RX_DESC_MAX + DEF_PKT_BURST +
+			RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;
+
+	test_params->mbuf_pool = rte_mempool_create("MBUF_POOL", nb_mbuf_per_pool,
+			MBUF_SIZE, MBUF_CACHE_SIZE, sizeof(struct rte_pktmbuf_pool_private),
+			rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
+			rte_socket_id(), 0);
+	if (test_params->mbuf_pool == NULL) {
+		printf("rte_mempool_create failed\n");
+		return -1;
+	}
+
+	/* Create / Initialize virtual eth devs */
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		char pmd_name[RTE_ETH_NAME_MAX_LEN];
+
+		mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i;
+
+		rte_snprintf(pmd_name, RTE_ETH_NAME_MAX_LEN, "test_slave_pmd_%d",i);
+
+		test_params->slave_port_ids[i] = virtual_ethdev_create(pmd_name,
+				mac_addr, rte_socket_id());
+		if (test_params->slave_port_ids[i] < 0) {
+			printf("Failed to create virtual pmd eth device.\n");
+			return -1;
+		}
+
+		retval = configure_ethdev(test_params->slave_port_ids[i], 1);
+		if (retval != 0) {
+			printf("Failed to configure virtual pmd eth device.\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+test_create_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	test_params->bonded_port_id = rte_eth_bond_create(BONDED_DEV_NAME,
+			test_params->bonding_mode, rte_socket_id());
+	if (test_params->bonded_port_id < 0) {
+		printf("\t Failed to create bonded device.\n");
+		return -1;
+	}
+
+	retval = configure_ethdev(test_params->bonded_port_id, 0);
+	if (retval != 0) {
+		printf("Failed to configure bonded pmd eth device.\n");
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			slaves, RTE_MAX_ETHPORTS);
+	if (current_slave_count > 0) {
+		printf("Number of slaves is great than expected.\n");
+		return -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 is great than expected.\n");
+		return -1;
+	}
+
+
+	if (rte_eth_bond_mode_get(test_params->bonded_port_id) !=
+			test_params->bonding_mode) {
+		printf("Bonded device mode not as expected.\n");
+		return -1;
+
+	}
+
+	return 0;
+}
+
+
+static int
+test_create_bonded_device_with_invalid_params(void)
+{
+	int port_id;
+
+	test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN;
+
+	/* Invalid name */
+	port_id = rte_eth_bond_create(NULL, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	test_params->bonding_mode = INVALID_BONDING_MODE;
+
+	/* Invalid bonding mode */
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN;
+
+	/* Invalid socket id */
+	port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode,
+			INVALID_SOCKET_ID);
+	if (port_id >= 0) {
+		printf("Created bonded device unexpectedly.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_add_slave_to_bonded_device(void)
+{
+	int retval, 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;
+	}
+
+	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;
+	}
+
+	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_params->bonded_slave_count++;
+
+	return 0;
+}
+
+static int
+test_add_slave_to_invalid_bonded_device(void)
+{
+	int retval;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_slave_add(test_params->bonded_port_id + 5,
+			test_params->slave_port_ids[test_params->bonded_slave_count]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_slave_add(test_params->slave_port_ids[0],
+			test_params->slave_port_ids[test_params->bonded_slave_count]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+test_remove_slave_from_bonded_device(void)
+{
+	int retval, 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;
+	}
+
+
+	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;
+	}
+
+
+	mac_addr = (struct ether_addr *)slave_mac;
+	mac_addr->addr_bytes[ETHER_ADDR_LEN-1] =
+			test_params->slave_port_ids[test_params->bonded_slave_count-1];
+
+	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;
+	}
+
+	rte_eth_stats_reset(
+			test_params->slave_port_ids[test_params->bonded_slave_count-1]);
+
+	virtual_ethdev_simulate_link_status_interrupt(test_params->bonded_port_id,
+			0);
+
+	test_params->bonded_slave_count--;
+
+	return 0;
+}
+
+static int
+test_remove_slave_from_invalid_bonded_device(void)
+{
+	int retval;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_slave_remove(test_params->bonded_port_id + 5,
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_slave_remove(test_params->slave_port_ids[0],
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_add_already_bonded_slave_to_bonded_device(void)
+{
+	int retval, port_id, current_slave_count;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+	char pmd_name[RTE_ETH_NAME_MAX_LEN];
+
+	test_add_slave_to_bonded_device();
+
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			slaves, RTE_MAX_ETHPORTS);
+	if (current_slave_count != 1) {
+		printf("Number of slaves (%d) is not that expected (%d).\n",
+				current_slave_count, 1);
+		return -1;
+	}
+
+	rte_snprintf(pmd_name, RTE_ETH_NAME_MAX_LEN, "%s_2",BONDED_DEV_NAME);
+
+	port_id = rte_eth_bond_create(pmd_name, test_params->bonding_mode,
+			rte_socket_id());
+	if (port_id < 0) {
+		printf("Failed to create bonded device.\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_slave_add(port_id,
+			test_params->slave_port_ids[test_params->bonded_slave_count - 1]);
+	if (retval == 0) {
+		printf("Added slave (%d) to bonded port (%d) unexpectedly.\n",
+				test_params->slave_port_ids[test_params->bonded_slave_count-1],
+				port_id);
+		return -1;
+	}
+
+	return test_remove_slave_from_bonded_device();
+}
+
+
+static int
+test_get_slaves_from_bonded_device(void)
+{
+	int retval, current_slave_count;
+
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	retval = test_add_slave_to_bonded_device();
+	if (retval != 0)
+		return -1;
+
+	/* Invalid port id */
+	current_slave_count = rte_eth_bond_slaves_get(INVALID_PORT_ID, slaves,
+			RTE_MAX_ETHPORTS);
+	if (current_slave_count >= 0)
+		return -1;
+
+	current_slave_count = rte_eth_bond_active_slaves_get(INVALID_PORT_ID,
+			slaves, RTE_MAX_ETHPORTS);
+	if (current_slave_count >= 0)
+		return -1;
+
+	/* Invalid slaves pointer */
+	current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id,
+			NULL, RTE_MAX_ETHPORTS);
+	if (current_slave_count >= 0)
+		return -1;
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, NULL, RTE_MAX_ETHPORTS);
+	if (current_slave_count >= 0)
+		return -1;
+
+	/* non bonded device*/
+	current_slave_count = rte_eth_bond_slaves_get(
+			test_params->slave_port_ids[0], NULL, RTE_MAX_ETHPORTS);
+	if (current_slave_count >= 0)
+		return -1;
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->slave_port_ids[0],	NULL, RTE_MAX_ETHPORTS);
+	if (current_slave_count >= 0)
+		return -1;
+
+	retval = test_remove_slave_from_bonded_device();
+	if (retval != 0)
+		return -1;
+
+	return 0;
+}
+
+
+static int
+test_add_remove_multiple_slaves_to_from_bonded_device(void)
+{
+	int i;
+
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		if (test_add_slave_to_bonded_device() != 0)
+			return -1;
+	}
+
+	for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) {
+		if (test_remove_slave_from_bonded_device() != 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+static void
+enable_bonded_slaves(void)
+{
+	int i;
+
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				test_params->slave_port_ids[i], 1);
+	}
+}
+
+static int
+test_start_bonded_device(void)
+{
+	struct rte_eth_link link_status;
+
+	int retval, current_slave_count, current_bonding_mode, primary_port;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	/* Add slave to bonded device*/
+	if (test_add_slave_to_bonded_device() != 0)
+		return -1;
+
+	retval = rte_eth_dev_start(test_params->bonded_port_id);
+	if (retval != 0) {
+		printf("Failed to start bonded pmd eth device.\n");
+		return -1;
+	}
+
+	/* Change link status of virtual pmd so it will be added to the active
+	 * slave list of the bonded device*/
+	virtual_ethdev_simulate_link_status_interrupt(
+			test_params->slave_port_ids[test_params->bonded_slave_count-1], 1);
+
+	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) {
+		printf("Number of slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_slave_count = rte_eth_bond_active_slaves_get(
+			test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS);
+	if (current_slave_count != test_params->bonded_slave_count) {
+		printf("Number of active slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -1;
+	}
+
+	current_bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id);
+	if (current_bonding_mode != test_params->bonding_mode) {
+		printf("Bonded device mode (%d) is not expected value (%d).\n",
+				current_bonding_mode, test_params->bonding_mode);
+		return -1;
+
+	}
+
+	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (primary_port != test_params->slave_port_ids[0]) {
+		printf("Primary port (%d) is not expected value (%d).\n",
+				primary_port, test_params->slave_port_ids[0]);
+		return -1;
+
+	}
+
+	rte_eth_link_get(test_params->bonded_port_id, &link_status);
+	if (!link_status.link_status) {
+		printf("Bonded port (%d) status (%d) is not expected value (%d).\n",
+				test_params->bonded_port_id, link_status.link_status, 1);
+		return -1;
+
+	}
+
+	return 0;
+}
+
+static int
+test_stop_bonded_device(void)
+{
+	int current_slave_count;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	struct rte_eth_link link_status;
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+
+	rte_eth_link_get(test_params->bonded_port_id, &link_status);
+	if (link_status.link_status) {
+		printf("Bonded port (%d) status (%d) is not expected value (%d).\n",
+				test_params->bonded_port_id, link_status.link_status, 0);
+		return -1;
+	}
+
+	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) {
+		printf("Number of slaves (%d) is not expected value (%d).\n",
+				current_slave_count, test_params->bonded_slave_count);
+		return -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 expected value (%d).\n",
+				current_slave_count, 0);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int remove_slaves_and_stop_bonded_device(void)
+{
+	/* Clean up and remove slaves from bonded device */
+	while (test_params->bonded_slave_count > 0) {
+		if (test_remove_slave_from_bonded_device() != 0) {
+			printf("test_remove_slave_from_bonded_device failed\n");
+			return -1;
+		}
+	}
+
+	rte_eth_dev_stop(test_params->bonded_port_id);
+	rte_eth_stats_reset(test_params->bonded_port_id);
+	rte_eth_bond_mac_address_reset(test_params->bonded_port_id);
+
+	return 0;
+}
+
+static int
+test_set_bonding_mode(void)
+{
+	int i;
+	int retval, bonding_mode;
+
+	int bonding_modes[] = { BONDING_MODE_ROUND_ROBIN,
+							BONDING_MODE_ACTIVE_BACKUP,
+							BONDING_MODE_BALANCE,
+							BONDING_MODE_BROADCAST };
+
+	/* Test supported link bonding modes */
+	for (i = 0; i < (int)RTE_DIM(bonding_modes);	i++) {
+		/* Invalid port ID */
+		retval = rte_eth_bond_mode_set(INVALID_PORT_ID, bonding_modes[i]);
+		if (retval == 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					INVALID_PORT_ID);
+			return -1;
+		}
+
+		/* Non bonded device */
+		retval = rte_eth_bond_mode_set(test_params->slave_port_ids[0],
+				bonding_modes[i]);
+		if (retval == 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					test_params->slave_port_ids[0]);
+			return -1;
+		}
+
+		retval = rte_eth_bond_mode_set(test_params->bonded_port_id,
+				bonding_modes[i]);
+		if (retval != 0) {
+			printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+					test_params->bonded_port_id, bonding_modes[i]);
+			return -1;
+		}
+
+		bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id);
+		if (bonding_mode != bonding_modes[i]) {
+			printf("Link bonding mode (%d) of port (%d) is not expected value (%d).\n",
+					bonding_mode, test_params->bonded_port_id,
+					bonding_modes[i]);
+			return -1;
+		}
+
+
+		/* Invalid port ID */
+		bonding_mode = rte_eth_bond_mode_get(INVALID_PORT_ID);
+		if (bonding_mode >= 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					INVALID_PORT_ID);
+			return -1;
+		}
+
+
+		/* Non bonded device */
+		bonding_mode = rte_eth_bond_mode_get(test_params->slave_port_ids[0]);
+		if (bonding_mode >= 0) {
+			printf("Expected call to failed as invalid port (%d) specified.\n",
+					test_params->slave_port_ids[0]);
+			return -1;
+		}
+
+	}
+
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+test_set_primary_slave(void)
+{
+	int i, j, retval;
+	struct ether_addr read_mac_addr;
+	struct ether_addr *expected_mac_addr;
+
+	/* Add 4 slaves to bonded device */
+	for (i = test_params->bonded_slave_count; i < 4; i++) {
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave to bonded device.\n");
+			return -1;
+		}
+	}
+	retval = rte_eth_bond_mode_set(test_params->bonded_port_id,
+			BONDING_MODE_ROUND_ROBIN);
+	if (retval != 0) {
+		printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+				test_params->bonded_port_id, BONDING_MODE_ROUND_ROBIN);
+		return -1;
+	}
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_primary_set(INVALID_PORT_ID,
+			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) {
+			printf("Failed to set bonded port (%d) primary port to (%d)\n",
+					test_params->bonded_port_id,
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+
+		retval = rte_eth_bond_primary_get(test_params->bonded_port_id);
+		if (retval < 0) {
+			printf("Failed to read primary port from bonded port (%d)\n",
+					test_params->bonded_port_id);
+			return -1;
+		} else if (retval != test_params->slave_port_ids[i]) {
+			printf("Bonded port (%d) primary port (%d) not expected value (%d)\n",
+					test_params->bonded_port_id, retval,
+					test_params->slave_port_ids[i]);
+			return -1;
+		}
+
+		/* 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;
+
+		expected_mac_addr = (struct ether_addr *)&slave_mac;
+		expected_mac_addr->addr_bytes[ETHER_ADDR_LEN-1] =
+				test_params->slave_port_ids[i];
+
+		/* Check primary slave MAC */
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(expected_mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("bonded port mac address not set to that of primary port\n");
+			return -1;
+		}
+
+		/* Check bonded MAC */
+		rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr);
+		if (memcmp(&read_mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("bonded port mac address not set to that of primary port\n");
+			return -1;
+		}
+
+		/* Check other slaves MACs */
+		for (j = 0; j < 4; j++) {
+			if (j != i) {
+				rte_eth_macaddr_get(test_params->slave_port_ids[j],
+						&read_mac_addr);
+				if (memcmp(expected_mac_addr, &read_mac_addr,
+						sizeof(read_mac_addr))) {
+					printf("slave port mac address not set to that of primary port\n");
+					return -1;
+				}
+			}
+		}
+	}
+
+
+	/* Test with none existent port */
+	retval = rte_eth_bond_primary_get(test_params->bonded_port_id + 10);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	/* Test with slave port */
+	retval = rte_eth_bond_primary_get(test_params->slave_port_ids[0]);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	if (remove_slaves_and_stop_bonded_device() != 0)
+		return -1;
+
+	/* No slaves  */
+	retval = rte_eth_bond_primary_get(test_params->bonded_port_id);
+	if (retval >= 0) {
+		printf("read primary port from expectedly\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+test_set_explicit_bonded_mac(void)
+{
+	int i, retval;
+	struct ether_addr read_mac_addr;
+	struct ether_addr *mac_addr;
+
+	uint8_t explicit_bonded_mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01 };
+
+	mac_addr = (struct ether_addr *)explicit_bonded_mac;
+
+	/* Invalid port ID */
+	retval = rte_eth_bond_mac_address_set(INVALID_PORT_ID, mac_addr);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* Non bonded device */
+	retval = rte_eth_bond_mac_address_set(test_params->slave_port_ids[0],
+			mac_addr);
+	if (retval == 0) {
+		printf("Expected call to failed as invalid port specified.\n");
+		return -1;
+	}
+
+	/* NULL MAC address */
+	retval = rte_eth_bond_mac_address_set(test_params->bonded_port_id, NULL);
+	if (retval == 0) {
+		printf("Expected call to failed as NULL MAC specified\n");
+		return -1;
+	}
+
+	retval = rte_eth_bond_mac_address_set(test_params->bonded_port_id,
+			mac_addr);
+	if (retval != 0) {
+		printf("Failed to set MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+		return -1;
+	}
+
+	/* Add 4 slaves to bonded device */
+	for (i = test_params->bonded_slave_count; i < 4; i++) {
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave to bonded device.\n");
+			return -1;
+		}
+	}
+
+	/* Check bonded MAC */
+	rte_eth_macaddr_get(test_params->bonded_port_id, &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;
+	}
+
+	/* Check other slaves MACs */
+	for (i = 0; i < 4; i++) {
+		rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr);
+		if (memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr))) {
+			printf("slave port mac address not set to that of primary port\n");
+			return -1;
+		}
+	}
+
+	/* test resetting mac address on bonded device */
+	if (rte_eth_bond_mac_address_reset(test_params->bonded_port_id) != 0) {
+		printf("Failed to reset MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+
+		return -1;
+	}
+
+	if (rte_eth_bond_mac_address_reset(test_params->slave_port_ids[0]) == 0) {
+		printf("Reset MAC address on bonded port (%d) unexpectedly\n",
+				test_params->slave_port_ids[1]);
+
+		return -1;
+	}
+
+	/* test resetting mac address on bonded device with no slaves */
+
+	if (remove_slaves_and_stop_bonded_device() != 0)
+		return -1;
+
+	if (rte_eth_bond_mac_address_reset(test_params->bonded_port_id) != 0) {
+		printf("Failed to reset MAC address on bonded port (%d)\n",
+				test_params->bonded_port_id);
+
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+initialize_bonded_device_with_slaves(uint8_t bonding_mode,
+		uint8_t number_of_slaves, uint8_t enable_slave)
+{
+	int retval;
+
+	/* configure bonded device */
+	retval = configure_ethdev(test_params->bonded_port_id, 0);
+	if (retval != 0) {
+		printf("Failed to configure bonding port (%d) in mode %d with (%d) slaves.\n",
+				test_params->bonded_port_id, bonding_mode, number_of_slaves);
+		return -1;
+	}
+
+	while (number_of_slaves > test_params->bonded_slave_count) {
+		/* Add slaves to bonded device */
+		retval = test_add_slave_to_bonded_device();
+		if (retval != 0) {
+			printf("Failed to add slave (%d to  bonding port (%d).\n",
+					test_params->bonded_slave_count - 1,
+					test_params->bonded_port_id);
+			return -1;
+		}
+	}
+
+	/* Set link bonding mode  */
+	retval = rte_eth_bond_mode_set(test_params->bonded_port_id, bonding_mode);
+	if (retval != 0) {
+		printf("Failed to set link bonding mode on port (%d) to (%d).\n",
+				test_params->bonded_port_id, bonding_mode);
+		return -1;
+	}
+
+	retval = rte_eth_dev_start(test_params->bonded_port_id);
+	if (retval != 0) {
+		printf("Failed to start bonded pmd eth device.\n");
+		return -1;
+	}
+
+	if (enable_slave)
+		enable_bonded_slaves();
+
+	return 0;
+}
+
+static int
+test_adding_slave_after_bonded_device_started(void)
+{
+	int i;
+
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 4, 0) !=
+			0)
+		return -1;
+
+	/* Enabled slave devices */
+	for (i = 0; i < test_params->bonded_slave_count + 1; i++) {
+		virtual_ethdev_simulate_link_status_interrupt(
+				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_params->bonded_slave_count++;
+
+	return remove_slaves_and_stop_bonded_device();
+}
+
+static int
+generate_test_burst(struct rte_mbuf **pkts_burst, uint16_t burst_size,
+		uint8_t vlan, uint8_t ipv4, uint8_t toggle_dst_mac,
+		uint8_t toggle_ip_addr, uint8_t toggle_udp_port)
+{
+	uint16_t pktlen, generated_burst_size;
+	void *ip_hdr;
+
+	if (toggle_dst_mac)
+		initialize_eth_header(test_params->pkt_eth_hdr,
+				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
+				vlan, vlan_id);
+	else
+		initialize_eth_header(test_params->pkt_eth_hdr,
+				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+				vlan, vlan_id);
+
+
+	if (toggle_udp_port)
+		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+				dst_port_1, 64);
+	else
+		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
+				dst_port_0, 64);
+
+	if (ipv4) {
+		if (toggle_ip_addr)
+			pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+					dst_addr_1, pktlen);
+		else
+			pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr,
+					dst_addr_0, pktlen);
+
+		ip_hdr = test_params->pkt_ipv4_hdr;
+	} else {
+		if (toggle_ip_addr)
+			pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr,
+					(uint8_t *)src_ipv6_addr, (uint8_t *)dst_ipv6_addr_1,
+					pktlen);
+		else
+			pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr,
+					(uint8_t *)src_ipv6_addr, (uint8_t *)dst_ipv6_addr_0,
+					pktlen);
+
+		ip_hdr = test_params->pkt_ipv6_hdr;
+	}
+
+	/* Generate burst of packets to transmit */
+	generated_burst_size = generate_packet_burst(test_params->mbuf_pool,
+			pkts_burst,	test_params->pkt_eth_hdr, vlan, ip_hdr, ipv4,
+			test_params->pkt_udp_hdr, burst_size);
+	if (generated_burst_size != burst_size) {
+		printf("Failed to generate packet burst");
+		return -1;
+	}
+
+	return generated_burst_size;
+}
+
+/** Round Robin Mode Tests */
+
+static int
+test_roundrobin_tx_burst(void)
+{
+	int i, burst_size, nb_tx;
+	struct rte_mbuf *pkt_burst[MAX_PKT_BURST];
+	struct rte_eth_stats port_stats;
+
+	if (initialize_bonded_device_with_slaves(BONDING_MODE_ROUND_ROBIN, 2, 1)
+			!= 0)
+		return -1;
+
+	burst_size = 20 * test_params->bonded_slave_count;
+
+	if (burst_size > MAX_PKT_BURST) {
+		printf("Burst size specified is greater than supported.\n");
+		return -1;
+	}
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0) != burst_size)
+		return -1;
+
+	/* Send burst on bonded port */
+	nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst,
+			burst_size);
+	if (nb_tx != burst_size)
+		return -1;
+
+	/* Verify bonded port tx stats */
+	rte_eth_stats_get(test_params->bonded_port_id, &port_stats);
+	if (port_stats.opackets != (uint64_t)burst_size) {
+		printf("Bonded Port (%d) opackets value (%u) not as expected (%d)\n",
+				test_params->bonded_port_id, (unsigned int)port_stats.opackets,
+				burst_size);
+		return -1;
+	}
+
+	/* Verify slave ports tx stats */
+	for (i = 0; i < test_params->bonded_slave_count; i++) {
+		rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats);
+		if (port_stats.opackets !=
+				(uint64_t)burst_size / test_params->bonded_slave_count) {
+			printf("Slave Port (%d)