All of lore.kernel.org
 help / color / mirror / Atom feed
From: Declan Doherty <declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
To: dev-VfR2kkLFssw@public.gmane.org
Subject: [PATCH v5 4/6] Link bonding Unit Tests
Date: Wed, 18 Jun 2014 17:14:21 +0100	[thread overview]
Message-ID: <1403108063-27169-5-git-send-email-declan.doherty@intel.com> (raw)
In-Reply-To: <1402917513-19495-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

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-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 app/test/Makefile                 |    4 +-
 app/test/commands.c               |    7 +
 app/test/packet_burst_generator.c |  287 +++
 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, 4982 insertions(+), 1 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

diff --git a/app/test/Makefile b/app/test/Makefile
index 9c52460..643f1b9 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -102,7 +102,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 c9dc085..5f23420 100644
--- a/app/test/commands.c
+++ b/app/test/commands.c
@@ -159,6 +159,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"))
@@ -227,6 +231,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..5d539f1
--- /dev/null
+++ b/app/test/packet_burst_generator.c
@@ -0,0 +1,287 @@
+/*-
+ *   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 c54e7ef..c00e1d6 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -97,6 +97,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..6662059
--- /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) 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;
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	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,
+			RTE_MAX_ETHPORTS);
+	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, RTE_MAX_ETHPORTS);
+	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, RTE_MAX_ETHPORTS) !=
+					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;
+
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	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,
+			RTE_MAX_ETHPORTS);
+	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, RTE_MAX_ETHPORTS);
+	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,
+			RTE_MAX_ETHPORTS) != 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,
+			RTE_MAX_ETHPORTS) != 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;
+
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	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,
+			RTE_MAX_ETHPORTS);
+	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, RTE_MAX_ETHPORTS);
+	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, RTE_MAX_ETHPORTS) != 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,
+			RTE_MAX_ETHPORTS) != 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;
+
+	uint8_t slaves[RTE_MAX_ETHPORTS];
+
+	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,
+			RTE_MAX_ETHPORTS);
+	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, RTE_MAX_ETHPORTS);
+	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, RTE_MAX_ETHPORTS);
+	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..0c67a10
--- /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(name);
+	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.7.0.7

  parent reply	other threads:[~2014-06-18 16:14 UTC|newest]

Thread overview: 127+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-05-28 15:32 [PATCH 0/4] Link Bonding Library declan.doherty-ral2JQCrhuEAvxtiuMwx3w
     [not found] ` <cover.1401287412.git.declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-05-28 15:32   ` [PATCH 1/4] " declan.doherty-ral2JQCrhuEAvxtiuMwx3w
     [not found]     ` <4d8e6bc2665fbaac641f0577714d7be9b0415d3c.1401287412.git.declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-05-28 16:54       ` Shaw, Jeffrey B
     [not found]         ` <4032A54B6BB5F04B8C08B6CFF08C59285543C357-AtyAts71sc9Qxe9IK+vIArfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-05-29 13:32           ` Doherty, Declan
2014-05-28 15:32   ` [PATCH 2/4] Link bonding unit tests declan.doherty-ral2JQCrhuEAvxtiuMwx3w
2014-05-28 15:32   ` [PATCH 3/4] Link bonding integration into testpmd declan.doherty-ral2JQCrhuEAvxtiuMwx3w
2014-05-28 15:32   ` [PATCH 4/4] Add Link Bonding Library to Doxygen declan.doherty-ral2JQCrhuEAvxtiuMwx3w
2014-05-28 17:49   ` [PATCH 0/4] Link Bonding Library Neil Horman
     [not found]     ` <20140528174908.GB2648-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2014-05-29 10:33       ` Doherty, Declan
     [not found]         ` <345C63BAECC1AD42A2EC8C63AFFC3ADC13D3327C-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-05-29 11:33           ` Neil Horman
2014-05-29  3:23   ` Cao, Waterman
     [not found]     ` <AA3F441F262C58498CD6D0C1801DE7EB0AA89A63-0J0gbvR4kTggGBtAFL8yw7fspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-05-29 10:35       ` Doherty, Declan
2014-06-04 15:18   ` [PATCH v2 " declan.doherty-ral2JQCrhuEAvxtiuMwx3w
2014-06-04 15:18   ` declan.doherty-ral2JQCrhuEAvxtiuMwx3w
     [not found]   ` <cover.1401891670.git.declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-04 15:18     ` [PATCH v2 1/4] " declan.doherty-ral2JQCrhuEAvxtiuMwx3w
     [not found]       ` <e6e8ecba5e2ba9d1a0e5299e042e7c54757e8644.1401891670.git.declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-05 15:15         ` Stephen Hemminger
     [not found]           ` <20140605081557.42a797e8-We1ePj4FEcvRI77zikRAJc56i+j3xesD0e7PPNI6Mm0@public.gmane.org>
2014-06-06  9:07             ` Doherty, Declan
     [not found]               ` <345C63BAECC1AD42A2EC8C63AFFC3ADC13D3737A-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-06-06 15:13                 ` Stephen Hemminger
2014-06-09 21:11         ` Eric Kinzie
     [not found]           ` <20140609211054.GA4853-5G/Vjf02Nsf/9pzu0YdTqQ@public.gmane.org>
2014-06-13 14:03             ` Doherty, Declan
2014-06-04 15:18     ` [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-ral2JQCrhuEAvxtiuMwx3w
2014-06-04 15:18     ` [PATCH v2 1/4] Link Bonding Library declan.doherty-ral2JQCrhuEAvxtiuMwx3w
2014-06-04 15:18     ` [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-ral2JQCrhuEAvxtiuMwx3w
2014-06-04 15:18     ` [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-ral2JQCrhuEAvxtiuMwx3w
2014-06-04 15:18     ` [PATCH v2 4/4] Add Link Bonding Library to Doxygen declan.doherty-ral2JQCrhuEAvxtiuMwx3w
2014-06-04 16:10     ` [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
     [not found]       ` <20140605110340.GB20841-B26myB8xz7F8NnZeBjwnZQMhkBWG/bsMQH7oEaQurus@public.gmane.org>
2014-06-06  8:23         ` Doherty, Declan
     [not found]           ` <345C63BAECC1AD42A2EC8C63AFFC3ADC13D37331-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-06-06 14:54             ` Neil Horman
     [not found]               ` <20140606145426.GA2543-B26myB8xz7F8NnZeBjwnZQMhkBWG/bsMQH7oEaQurus@public.gmane.org>
2014-06-13 14:56                 ` Doherty, Declan
     [not found]                   ` <345C63BAECC1AD42A2EC8C63AFFC3ADC13D38DBF-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-06-13 15:11                     ` Neil Horman
2014-06-06  3:26     ` Cao, Waterman
2014-06-11 16:33     ` Thomas Monjalon
2014-06-13 14:08       ` Doherty, Declan
     [not found]         ` <345C63BAECC1AD42A2EC8C63AFFC3ADC13D38CDE-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-06-13 15:15           ` Thomas Monjalon
2014-06-13 14:41   ` [PATCH v3 0/5] Link Bonding PMD Library Declan Doherty
2014-06-13 14:41   ` [PATCH v3 1/5] " Declan Doherty
2014-06-13 14:41   ` [PATCH v3 2/5] Link Bonding PMD Library (librte_eal/librte_ether link bonding support changes) Declan Doherty
     [not found]     ` <258914f35917ae07dddc991ac9726542964dce44.1402662300.git.declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-13 16:08       ` Neil Horman
     [not found]         ` <20140613160807.GD22451-B26myB8xz7F8NnZeBjwnZQMhkBWG/bsMQH7oEaQurus@public.gmane.org>
2014-06-13 18:34           ` Doherty, Declan
     [not found]             ` <345C63BAECC1AD42A2EC8C63AFFC3ADC13D38EE9-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-06-13 19:38               ` Neil Horman
     [not found]                 ` <20140613193815.GE22451-B26myB8xz7F8NnZeBjwnZQMhkBWG/bsMQH7oEaQurus@public.gmane.org>
2014-06-16  8:59                   ` Doherty, Declan
     [not found]                     ` <345C63BAECC1AD42A2EC8C63AFFC3ADC13D39383-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-06-16 11:07                       ` Neil Horman
     [not found]                         ` <20140616110758.GA15165-B26myB8xz7F8NnZeBjwnZQMhkBWG/bsMQH7oEaQurus@public.gmane.org>
2014-06-16 16:17                           ` Richardson, Bruce
     [not found]                             ` <59AF69C657FD0841A61C55336867B5B01AA368CE-kPTMFJFq+rELt2AQoY/u9bfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-06-16 17:47                               ` Neil Horman
     [not found]                                 ` <20140616174746.GC15165-B26myB8xz7F8NnZeBjwnZQMhkBWG/bsMQH7oEaQurus@public.gmane.org>
2014-06-16 18:07                                   ` Richardson, Bruce
2014-06-16 18:09                                   ` Thomas Monjalon
2014-06-13 21:59       ` Stephen Hemminger
     [not found]         ` <20140613145918.5faebfde-We1ePj4FEcvRI77zikRAJc56i+j3xesD0e7PPNI6Mm0@public.gmane.org>
2014-06-16  7:59           ` Doherty, Declan
2014-06-13 14:42   ` [PATCH v3 3/5] Link Bonding PMD Library (Unit Test Suite) Declan Doherty
2014-06-13 14:42   ` [PATCH v3 4/5] Link Bonding PMD Library (testpmd link bonding API support) Declan Doherty
2014-06-13 14:42   ` [PATCH v3 5/5] Link Bonding PMD Library (Doxygen Additions) Declan Doherty
     [not found] ` <cover.1402662300.git.declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-13 15:20   ` [PATCH v3 0/5] Link Bonding PMD Library Neil Horman
2014-06-16 11:18   ` [PATCH v4 0/6] Link Bonding Library Declan Doherty
     [not found]     ` <1402917513-19495-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-18 16:14       ` [PATCH v5 " Declan Doherty
     [not found]         ` <1403108063-27169-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-18 16:18           ` Neil Horman
2014-06-24 14:52           ` [PATCH v6 " Declan Doherty
     [not found]             ` <1403621531-30487-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-24 16:03               ` [PATCH v7 " Declan Doherty
     [not found]                 ` <1403625828-20956-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-25 20:07                   ` [PATCH v8 " Declan Doherty
     [not found]                     ` <1403726868-8161-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-26 16:02                       ` De Lara Guarch, Pablo
2014-06-26 23:57                       ` [PATCH v9 0/5] link bonding Thomas Monjalon
     [not found]                         ` <1403827075-9192-1-git-send-email-thomas.monjalon-pdR9zngts4EAvxtiuMwx3w@public.gmane.org>
2014-06-26 23:57                           ` [PATCH v9 1/5] bond: new link bonding library Thomas Monjalon
     [not found]                             ` <1403827075-9192-2-git-send-email-thomas.monjalon-pdR9zngts4EAvxtiuMwx3w@public.gmane.org>
2014-06-27  0:45                               ` Thomas Monjalon
2014-06-26 23:57                           ` [PATCH v9 2/5] ethdev: add unique name to devices Thomas Monjalon
2014-06-26 23:57                           ` [PATCH v9 3/5] eal: support link bonding device initialization Thomas Monjalon
2014-06-26 23:57                           ` [PATCH v9 4/5] bond: unit tests Thomas Monjalon
2014-06-26 23:57                           ` [PATCH v9 5/5] bond: testpmd support Thomas Monjalon
2014-06-27 10:18                           ` [PATCH v10 0/5] link bonding Declan Doherty
     [not found]                             ` <1403864324-12022-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-27 20:58                               ` Thomas Monjalon
2014-06-29 17:49                               ` [PATCH v11 0/5] link bonding library Declan Doherty
     [not found]                                 ` <1404064161-26370-1-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-30  9:21                                   ` Thomas Monjalon
2014-06-30  9:28                                     ` Doherty, Declan
     [not found]                                       ` <345C63BAECC1AD42A2EC8C63AFFC3ADC2730631F-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-07-01 22:01                                         ` Thomas Monjalon
2014-06-29 17:49                               ` [PATCH v11 1/5] bond: new " Declan Doherty
     [not found]                                 ` <1404064161-26370-2-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-30  9:13                                   ` Thomas Monjalon
2014-06-30 22:29                                   ` Robert Sanford
     [not found]                                     ` <CA+cr1cojs0sx5s1ohwVcdT6ojQ_7PEwEAqmtCca0LAz_jkvVdw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-01 14:16                                       ` Thomas Monjalon
2014-07-01 14:19                                       ` Doherty, Declan
     [not found]                                         ` <345C63BAECC1AD42A2EC8C63AFFC3ADC273077A5-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-07-01 14:26                                           ` Thomas Monjalon
2014-06-29 17:49                               ` [PATCH v11 2/5] ethdev: add unique name to devices Declan Doherty
2014-06-29 17:49                               ` [PATCH v11 3/5] eal: support link bonding device initialization Declan Doherty
2014-06-29 17:49                               ` [PATCH v11 4/5] bond: unit tests Declan Doherty
     [not found]                                 ` <1404064161-26370-5-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-30  8:56                                   ` Thomas Monjalon
2014-06-29 17:49                               ` [PATCH v11 5/5] bond: testpmd support Declan Doherty
2014-06-27 10:18                           ` [PATCH v10 1/5] bond: new link bonding library Declan Doherty
2014-06-27 10:18                           ` [PATCH v10 2/5] ethdev: add unique name to devices Declan Doherty
2014-06-27 10:18                           ` [PATCH v10 3/5] eal: support link bonding device initialization Declan Doherty
2014-06-27 10:18                           ` [PATCH v10 4/5] bond: unit tests Declan Doherty
2014-06-27 10:18                           ` [PATCH v10 5/5] bond: testpmd support Declan Doherty
2014-06-25 20:07                   ` [PATCH v8 1/6] Link Bonding Library (lib/librte_pmd_bond) Declan Doherty
2014-06-25 20:07                   ` [PATCH v8 2/6] Support for unique interface naming of pmds Declan Doherty
2014-06-25 20:07                   ` [PATCH v8 3/6] EAL support for link bonding device initialization Declan Doherty
2014-06-25 20:07                   ` [PATCH v8 4/6] Link bonding Unit Tests Declan Doherty
2014-06-25 20:07                   ` [PATCH v8 5/6] testpmd link bonding additions Declan Doherty
2014-06-25 20:07                   ` [PATCH v8 6/6] Link Bonding Library doxygen additions Declan Doherty
2014-06-24 16:03               ` [PATCH v7 1/6] Link Bonding Library (lib/librte_pmd_bond) Declan Doherty
2014-06-24 16:03               ` [PATCH v7 2/6] Support for unique interface naming of pmds Declan Doherty
2014-06-24 16:03               ` [PATCH v7 3/6] EAL support for link bonding device initialization Declan Doherty
     [not found]                 ` <1403625828-20956-4-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-25 13:54                   ` Thomas Monjalon
2014-06-25 14:41                     ` Doherty, Declan
     [not found]                       ` <345C63BAECC1AD42A2EC8C63AFFC3ADC272FB41C-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-06-25 16:00                         ` Thomas Monjalon
2014-06-25 16:15                           ` Richardson, Bruce
2014-06-24 16:03               ` [PATCH v7 4/6] Link bonding Unit Tests Declan Doherty
2014-06-24 16:03               ` [PATCH v7 5/6] testpmd link bonding additions Declan Doherty
2014-06-24 16:03               ` [PATCH v7 6/6] Link Bonding Library doxygen additions Declan Doherty
     [not found]                 ` <1403625828-20956-7-git-send-email-declan.doherty-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2014-06-25 13:43                   ` Thomas Monjalon
2014-06-25 14:19                     ` Doherty, Declan
     [not found]                       ` <345C63BAECC1AD42A2EC8C63AFFC3ADC272FA3EA-kPTMFJFq+rF9qrmMLTLiibfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2014-06-25 14:23                         ` Thomas Monjalon
2014-06-24 14:52           ` [PATCH v6 1/6] Link Bonding Library (lib/librte_pmd_bond) Declan Doherty
2014-06-24 14:52           ` [PATCH v6 2/6] Support for unique interface naming of pmds Declan Doherty
2014-06-24 14:52           ` [PATCH v6 3/6] EAL support for link bonding device initialization Declan Doherty
2014-06-24 14:52           ` [PATCH v6 4/6] Link bonding Unit Tests Declan Doherty
2014-06-24 14:52           ` [PATCH v6 5/6] testpmd link bonding additions Declan Doherty
2014-06-24 14:52           ` [PATCH v6 6/6] Link Bonding Library doxygen additions Declan Doherty
2014-06-18 16:14       ` [PATCH v5 1/6] Link Bonding Library (lib/librte_pmd_bond) Declan Doherty
2014-06-18 16:14       ` [PATCH v5 2/6] Support for unique interface naming of pmds Declan Doherty
2014-06-18 16:14       ` [PATCH v5 3/6] EAL support for link bonding device initialization Declan Doherty
2014-06-18 16:14       ` Declan Doherty [this message]
2014-06-18 16:14       ` [PATCH v5 5/6] testpmd link bonding additions Declan Doherty
2014-06-18 16:14       ` [PATCH v5 6/6] Link Bonding Library doxygen additions Declan Doherty
2014-06-16 11:18   ` [PATCH v4 1/6] 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, la Mode 3 - Broadcast Declan Doherty
2014-06-16 11:18   ` [PATCH v4 2/6] Support for unique interface naming of pmds Declan Doherty
2014-06-16 11:18   ` [PATCH v4 3/6] EAL support for link bonding device initialization Declan Doherty
2014-06-16 11:18   ` [PATCH v4 4/6] Link bonding Unit Tests Declan Doherty
2014-06-16 11:18   ` [PATCH v4 5/6] testpmd link bonding additions Declan Doherty
2014-06-16 11:18   ` [PATCH v4 6/6] Link Bonding Library doxygen additions Declan Doherty

Reply instructions:

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

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

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

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

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

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

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