DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB)
@ 2015-02-13 15:16 Michal Jastrzebski
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
                   ` (8 more replies)
  0 siblings, 9 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-13 15:16 UTC (permalink / raw)
  To: dev

This patchset add support for link bonding mode 6.
Additionally it changes an arp_header structure definition.
Also a basic example is introduced. Using this example,
Bonding will configure each client ARP table,
that packets from each client will be received on different slave,
mode 6 uses round-robin policy to assign slave to client IP address.

Michal Jastrzebski (6):
  net: changed arp_hdr struct declaration
  bond: add link bonding mode 6 implementation
  bond: add debug info for mode 6 link bonding
  bond: add example application for link bonding mode 6
  bond: modify TLB unit tests
  bond: add unit tests for link bonding mode 6.

 app/test-pmd/icmpecho.c                    |   27 +-
 app/test/packet_burst_generator.c          |   41 +-
 app/test/packet_burst_generator.h          |   11 +-
 app/test/test_link_bonding.c               |  422 ++++++++++++++-
 app/test/test_pmd_perf.c                   |    3 +-
 app/test/virtual_pmd.c                     |  103 ++--
 app/test/virtual_pmd.h                     |    5 +-
 config/common_linuxapp                     |    3 +-
 examples/bond/Makefile                     |   57 ++
 examples/bond/main.c                       |  792 ++++++++++++++++++++++++++++
 examples/bond/main.h                       |   46 ++
 lib/librte_net/rte_arp.h                   |   13 +-
 lib/librte_pmd_bond/Makefile               |    1 +
 lib/librte_pmd_bond/rte_eth_bond.h         |   11 +-
 lib/librte_pmd_bond/rte_eth_bond_alb.c     |  256 +++++++++
 lib/librte_pmd_bond/rte_eth_bond_alb.h     |  109 ++++
 lib/librte_pmd_bond/rte_eth_bond_api.c     |   28 +-
 lib/librte_pmd_bond/rte_eth_bond_args.c    |    3 +-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  460 ++++++++++++++--
 lib/librte_pmd_bond/rte_eth_bond_private.h |   12 +
 20 files changed, 2257 insertions(+), 146 deletions(-)
 create mode 100644 examples/bond/Makefile
 create mode 100644 examples/bond/main.c
 create mode 100644 examples/bond/main.h
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h

-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v2 1/6] net: changed arp_hdr struct declaration
  2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
@ 2015-02-13 15:16 ` Michal Jastrzebski
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 2/6] bond: add link bonding mode 6 implementation Michal Jastrzebski
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-13 15:16 UTC (permalink / raw)
  To: dev

Changed MAC address type from uint8_t[6] to struct ether_addr and IP
address type from uint8_t[4] to uint32_t. Also removed union from
arp_hdr struct. Updated test-pmd to match new arp_hdr version.

Signed-off-by: Maciej Gajdzica  <maciejx.t.gajdzica@intel.com>
---
 app/test-pmd/icmpecho.c  |   27 ++++++++++-----------------
 lib/librte_net/rte_arp.h |   13 ++++++-------
 2 files changed, 16 insertions(+), 24 deletions(-)

diff --git a/app/test-pmd/icmpecho.c b/app/test-pmd/icmpecho.c
index 08ea01d..010c5a9 100644
--- a/app/test-pmd/icmpecho.c
+++ b/app/test-pmd/icmpecho.c
@@ -371,18 +371,14 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 				continue;
 			}
 			if (verbose_level > 0) {
-				memcpy(&eth_addr,
-				       arp_h->arp_data.arp_ip.arp_sha, 6);
+				ether_addr_copy(&arp_h->arp_data.arp_sha, &eth_addr);
 				ether_addr_dump("        sha=", &eth_addr);
-				memcpy(&ip_addr,
-				       arp_h->arp_data.arp_ip.arp_sip, 4);
+				ip_addr = arp_h->arp_data.arp_sip;
 				ipv4_addr_dump(" sip=", ip_addr);
 				printf("\n");
-				memcpy(&eth_addr,
-				       arp_h->arp_data.arp_ip.arp_tha, 6);
+				ether_addr_copy(&arp_h->arp_data.arp_tha, &eth_addr);
 				ether_addr_dump("        tha=", &eth_addr);
-				memcpy(&ip_addr,
-				       arp_h->arp_data.arp_ip.arp_tip, 4);
+				ip_addr = arp_h->arp_data.arp_tip;
 				ipv4_addr_dump(" tip=", ip_addr);
 				printf("\n");
 			}
@@ -402,17 +398,14 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 					&eth_h->s_addr);
 
 			arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
-			memcpy(&eth_addr, arp_h->arp_data.arp_ip.arp_tha, 6);
-			memcpy(arp_h->arp_data.arp_ip.arp_tha,
-			       arp_h->arp_data.arp_ip.arp_sha, 6);
-			memcpy(arp_h->arp_data.arp_ip.arp_sha,
-			       &eth_h->s_addr, 6);
+			ether_addr_copy(&arp_h->arp_data.arp_tha, &eth_addr);
+			ether_addr_copy(&arp_h->arp_data.arp_sha, &arp_h->arp_data.arp_tha);
+			ether_addr_copy(&eth_addr, &arp_h->arp_data.arp_sha);
 
 			/* Swap IP addresses in ARP payload */
-			memcpy(&ip_addr, arp_h->arp_data.arp_ip.arp_sip, 4);
-			memcpy(arp_h->arp_data.arp_ip.arp_sip,
-			       arp_h->arp_data.arp_ip.arp_tip, 4);
-			memcpy(arp_h->arp_data.arp_ip.arp_tip, &ip_addr, 4);
+			ip_addr = arp_h->arp_data.arp_sip;
+			arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
+			arp_h->arp_data.arp_tip = ip_addr;
 			pkts_burst[nb_replies++] = pkt;
 			continue;
 		}
diff --git a/lib/librte_net/rte_arp.h b/lib/librte_net/rte_arp.h
index c7b0e51..72108a1 100644
--- a/lib/librte_net/rte_arp.h
+++ b/lib/librte_net/rte_arp.h
@@ -39,6 +39,7 @@
  */
 
 #include <stdint.h>
+#include <rte_ether.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -48,10 +49,10 @@ extern "C" {
  * ARP header IPv4 payload.
  */
 struct arp_ipv4 {
-	uint8_t  arp_sha[6]; /* sender hardware address */
-	uint8_t  arp_sip[4]; /* sender IP address */
-	uint8_t  arp_tha[6]; /* target hardware address */
-	uint8_t  arp_tip[4]; /* target IP address */
+	struct ether_addr  arp_sha;	/* sender hardware address */
+	uint32_t  arp_sip;			/* sender IP address */
+	struct ether_addr  arp_tha;	/* target hardware address */
+	uint32_t  arp_tip;			/* target IP address */
 } __attribute__((__packed__));
 
 /**
@@ -72,9 +73,7 @@ struct arp_hdr {
 #define	ARP_OP_INVREQUEST 8 /* request to identify peer */
 #define	ARP_OP_INVREPLY   9 /* response identifying peer */
 
-	union {
-		struct arp_ipv4 arp_ip;
-	} arp_data;
+	struct arp_ipv4 arp_data;
 } __attribute__((__packed__));
 
 #ifdef __cplusplus
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v2 2/6] bond: add link bonding mode 6 implementation
  2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
@ 2015-02-13 15:16 ` Michal Jastrzebski
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 3/6] bond: add debug info for mode 6 link bonding Michal Jastrzebski
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-13 15:16 UTC (permalink / raw)
  To: dev

v2 changes
- add VLAN support
- fixed sending duplicated ARPupdates
- fixed assigning slaves for next clients
- fixed TLB mode

This mode includes adaptive TLB and receive load balancing (RLB). In RLB
the bonding driver intercepts ARP replies send by local system and
overwrites its source MAC address, so that different peers send data to
the server on different slave interfaces. When local system sends ARP
request, it saves IP information from it. When ARP reply from that peer
is received, its MAC is stored, one of slave MACs assigned and ARP reply
send to that peer.

Signed-off-by: Maciej Gajdzica  <maciejx.t.gajdzica@intel.com>
Signed-off-by: Michal Jastrzebski  <michalx.k.jastrzebski@intel.com>
Signed-off-by: Daniel Mrzyglod  <danielx.t.mrzyglod@intel.com>
---
 lib/librte_pmd_bond/Makefile               |    1 +
 lib/librte_pmd_bond/rte_eth_bond.h         |    9 +
 lib/librte_pmd_bond/rte_eth_bond_alb.c     |  256 +++++++++++++++++++++++++++
 lib/librte_pmd_bond/rte_eth_bond_alb.h     |  109 ++++++++++++
 lib/librte_pmd_bond/rte_eth_bond_api.c     |   28 ++-
 lib/librte_pmd_bond/rte_eth_bond_args.c    |    1 +
 lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  259 ++++++++++++++++++++++++----
 lib/librte_pmd_bond/rte_eth_bond_private.h |   12 ++
 8 files changed, 640 insertions(+), 35 deletions(-)
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h

diff --git a/lib/librte_pmd_bond/Makefile b/lib/librte_pmd_bond/Makefile
index d6c81a8..cb16356 100644
--- a/lib/librte_pmd_bond/Makefile
+++ b/lib/librte_pmd_bond/Makefile
@@ -50,6 +50,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_api.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_pmd.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_8023ad.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_alb.c
 
 ifeq ($(CONFIG_RTE_MBUF_REFCNT),n)
 $(info WARNING: Link Bonding Broadcast mode is disabled because it needs MBUF_REFCNT.)
diff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h
index 7177983..13581cb 100644
--- a/lib/librte_pmd_bond/rte_eth_bond.h
+++ b/lib/librte_pmd_bond/rte_eth_bond.h
@@ -101,6 +101,15 @@ extern "C" {
  * This mode provides an adaptive transmit load balancing. It dynamically
  * changes the transmitting slave, according to the computed load. Statistics
  * are collected in 100ms intervals and scheduled every 10ms */
+#define BONDING_MODE_ALB	(6)
+/**< Adaptive Load Balancing (Mode 6)
+ * This mode includes adaptive TLB and receive load balancing (RLB). In RLB the
+ * bonding driver intercepts ARP replies send by local system and overwrites its
+ * source MAC address, so that different peers send data to the server on
+ * different slave interfaces. When local system sends ARP request, it saves IP
+ * information from it. When ARP reply from that peer is received, its MAC is
+ * stored, one of slave MACs assigned and ARP reply send to that peer.
+ */
 
 /* Balance Mode Transmit Policies */
 #define BALANCE_XMIT_POLICY_LAYER2		(0)
diff --git a/lib/librte_pmd_bond/rte_eth_bond_alb.c b/lib/librte_pmd_bond/rte_eth_bond_alb.c
new file mode 100644
index 0000000..97afd80
--- /dev/null
+++ b/lib/librte_pmd_bond/rte_eth_bond_alb.c
@@ -0,0 +1,256 @@
+#include "rte_eth_bond_private.h"
+#include "rte_eth_bond_alb.h"
+
+static inline uint8_t
+simple_hash(uint8_t *hash_start, int hash_size)
+{
+	int i;
+	uint8_t hash;
+
+	hash = 0;
+	for (i = 0; i < hash_size; ++i)
+		hash ^= hash_start[i];
+
+	return hash;
+}
+
+static uint8_t
+calculate_slave(struct bond_dev_private *internals)
+{
+	uint8_t idx;
+
+	idx = (internals->mode6.last_slave + 1) % internals->active_slave_count;
+	internals->mode6.last_slave = idx;
+	return internals->active_slaves[idx];
+}
+
+int
+bond_mode_alb_enable(struct rte_eth_dev *bond_dev)
+{
+	struct bond_dev_private *internals = bond_dev->data->dev_private;
+	struct client_data *hash_table = internals->mode6.client_table;
+
+	uint16_t element_size;
+	char mem_name[RTE_ETH_NAME_MAX_LEN];
+	int socket_id = bond_dev->pci_dev->numa_node;
+
+	/* Fill hash table with initial values */
+	memset(hash_table, 0, sizeof(struct client_data) * ALB_HASH_TABLE_SIZE);
+	rte_spinlock_init(&internals->mode6.lock);
+	internals->mode6.last_slave = ALB_NULL_INDEX;
+	internals->mode6.ntt = 0;
+
+	/* Initialize memory pool for ARP packets to send */
+	if (internals->mode6.mempool == NULL) {
+		/*
+		 * 256 is size of ETH header, ARP header and nested VLAN headers.
+		 * The value is chosen to be cache aligned.
+		 */
+		element_size = 256 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM;
+		snprintf(mem_name, sizeof(mem_name), "%s_MODE6", bond_dev->data->name);
+		internals->mode6.mempool = rte_mempool_create(mem_name,
+				512 * RTE_MAX_ETHPORTS,
+				element_size,
+				RTE_MEMPOOL_CACHE_MAX_SIZE >= 32 ?
+						32 : RTE_MEMPOOL_CACHE_MAX_SIZE,
+				sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init,
+				NULL, rte_pktmbuf_init, NULL, socket_id, 0);
+
+		if (internals->mode6.mempool == NULL) {
+			RTE_LOG(ERR, PMD, "%s: Failed to initialize ALB mempool.\n",
+					bond_dev->data->name);
+			rte_panic(
+					"Failed to alocate memory pool ('%s')\n" "for bond device '%s'\n",
+					mem_name, bond_dev->data->name);
+		}
+	}
+
+	return 0;
+}
+
+void bond_mode_alb_arp_recv(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals) {
+	struct arp_hdr *arp;
+
+	struct client_data *hash_table = internals->mode6.client_table;
+	struct client_data *client_info;
+
+	uint8_t hash_index;
+
+	arp = (struct arp_hdr *) ((char *) (eth_h + 1) + offset);
+
+	/* ARP Requests are forwarded to the application with no changes */
+	if (arp->arp_op != rte_cpu_to_be_16(ARP_OP_REPLY))
+		return;
+
+	/* From now on, we analyze only ARP Reply packets */
+	hash_index = simple_hash((uint8_t *) &arp->arp_data.arp_sip,
+			sizeof(arp->arp_data.arp_sip));
+	client_info = &hash_table[hash_index];
+
+	/*
+	 * We got reply for ARP Request send by the application. We need to
+	 * update client table when received data differ from what is stored
+	 * in ALB table and issue sending update packet to that slave.
+	 */
+	rte_spinlock_lock(&internals->mode6.lock);
+	if (client_info->in_use == 0 ||
+			client_info->app_ip != arp->arp_data.arp_tip ||
+			client_info->cli_ip != arp->arp_data.arp_sip ||
+			!is_same_ether_addr(&client_info->cli_mac, &arp->arp_data.arp_sha) ||
+			client_info->vlan_count != offset / sizeof(struct vlan_hdr) ||
+			memcmp(client_info->vlan, eth_h + 1, offset) != 0
+	) {
+		client_info->in_use = 1;
+		client_info->app_ip = arp->arp_data.arp_tip;
+		client_info->cli_ip = arp->arp_data.arp_sip;
+		ether_addr_copy(&arp->arp_data.arp_sha, &client_info->cli_mac);
+		client_info->slave_idx = calculate_slave(internals);
+		rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+		ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_tha);
+		memcpy(client_info->vlan, eth_h + 1, offset);
+		client_info->vlan_count = offset / sizeof(struct vlan_hdr);
+	}
+	internals->mode6.ntt = 1;
+	rte_spinlock_unlock(&internals->mode6.lock);
+}
+
+uint8_t
+bond_mode_alb_arp_xmit(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals)
+{
+	struct arp_hdr *arp;
+
+	struct client_data *hash_table = internals->mode6.client_table;
+	struct client_data *client_info;
+
+	uint8_t hash_index;
+
+	struct ether_addr bonding_mac;
+
+	arp = (struct arp_hdr *)((char *)(eth_h + 1) + offset);
+
+	/*
+	 * Traffic with src MAC other than bonding should be sent on
+	 * current primary port.
+	 */
+	rte_eth_macaddr_get(internals->port_id, &bonding_mac);
+	if (!is_same_ether_addr(&bonding_mac, &arp->arp_data.arp_sha)) {
+		rte_eth_macaddr_get(internals->current_primary_port,
+				&arp->arp_data.arp_sha);
+		return internals->current_primary_port;
+	}
+
+	hash_index = simple_hash((uint8_t *)&arp->arp_data.arp_tip,
+			sizeof(uint32_t));
+	client_info = &hash_table[hash_index];
+
+	rte_spinlock_lock(&internals->mode6.lock);
+	if (arp->arp_op == rte_cpu_to_be_16(ARP_OP_REPLY)) {
+		if (client_info->in_use) {
+			if (client_info->app_ip == arp->arp_data.arp_sip &&
+				client_info->cli_ip == arp->arp_data.arp_tip) {
+				/* Entry is already assigned to this client */
+				if (!is_broadcast_ether_addr(&arp->arp_data.arp_tha)) {
+					ether_addr_copy(&arp->arp_data.arp_tha,
+							&client_info->cli_mac);
+				}
+				rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+				ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);
+				memcpy(client_info->vlan, eth_h + 1, offset);
+				client_info->vlan_count = offset / sizeof(struct vlan_hdr);
+				rte_spinlock_unlock(&internals->mode6.lock);
+				return client_info->slave_idx;
+			}
+		}
+
+		/* Assign new slave to this client and update src mac in ARP */
+		client_info->in_use = 1;
+		client_info->ntt = 0;
+		client_info->app_ip = arp->arp_data.arp_sip;
+		ether_addr_copy(&arp->arp_data.arp_tha, &client_info->cli_mac);
+		client_info->cli_ip = arp->arp_data.arp_tip;
+		client_info->slave_idx = calculate_slave(internals);
+		rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+		ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);
+		memcpy(client_info->vlan, eth_h + 1, offset);
+		client_info->vlan_count = offset / sizeof(struct vlan_hdr);
+		rte_spinlock_unlock(&internals->mode6.lock);
+		return client_info->slave_idx;
+	}
+
+	/* If packet is not ARP Reply, send it on current primary port. */
+	rte_spinlock_unlock(&internals->mode6.lock);
+	rte_eth_macaddr_get(internals->current_primary_port,
+			&arp->arp_data.arp_sha);
+	return internals->current_primary_port;
+}
+
+uint8_t
+bond_mode_alb_arp_upd(struct client_data *client_info,
+		struct rte_mbuf *pkt, struct bond_dev_private *internals)
+{
+	struct ether_hdr *eth_h;
+	struct arp_hdr *arp_h;
+	uint8_t slave_idx;
+
+	rte_spinlock_lock(&internals->mode6.lock);
+	eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+
+	ether_addr_copy(&client_info->app_mac, &eth_h->s_addr);
+	ether_addr_copy(&client_info->cli_mac, &eth_h->d_addr);
+	if (client_info->vlan_count > 0)	{
+		eth_h->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+		}
+	else	{
+		eth_h->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+	}
+
+	arp_h = (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr)
+			+ client_info->vlan_count * sizeof(struct vlan_hdr));
+
+	memcpy(eth_h + 1, client_info->vlan,
+			client_info->vlan_count * sizeof(struct vlan_hdr));
+
+	ether_addr_copy(&client_info->app_mac, &arp_h->arp_data.arp_sha);
+	arp_h->arp_data.arp_sip = client_info->app_ip;
+	ether_addr_copy(&client_info->cli_mac, &arp_h->arp_data.arp_tha);
+	arp_h->arp_data.arp_tip = client_info->cli_ip;
+
+	arp_h->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
+	arp_h->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	arp_h->arp_hln = ETHER_ADDR_LEN;
+	arp_h->arp_pln = sizeof(uint32_t);
+	arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
+
+	slave_idx = client_info->slave_idx;
+	rte_spinlock_unlock(&internals->mode6.lock);
+
+	return slave_idx;
+}
+
+void
+bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev)
+{
+	struct bond_dev_private *internals = bond_dev->data->dev_private;
+	struct client_data *client_info;
+
+	int i;
+
+	/* If active slave count is 0, it's pointless to refresh alb table */
+	if (internals->active_slave_count <= 0)
+		return;
+
+	rte_spinlock_lock(&internals->mode6.lock);
+	internals->mode6.last_slave = ALB_NULL_INDEX;
+
+	for (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {
+		client_info = &internals->mode6.client_table[i];
+		if (client_info->in_use) {
+			client_info->slave_idx = calculate_slave(internals);
+			rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+			internals->mode6.ntt = 1;
+		}
+	}
+	rte_spinlock_unlock(&internals->mode6.lock);
+}
diff --git a/lib/librte_pmd_bond/rte_eth_bond_alb.h b/lib/librte_pmd_bond/rte_eth_bond_alb.h
new file mode 100644
index 0000000..0cfe942
--- /dev/null
+++ b/lib/librte_pmd_bond/rte_eth_bond_alb.h
@@ -0,0 +1,109 @@
+#ifndef RTE_ETH_BOND_ALB_H_
+#define RTE_ETH_BOND_ALB_H_
+
+#include <rte_ether.h>
+#include <rte_arp.h>
+
+#define ALB_HASH_TABLE_SIZE	256
+#define ALB_NULL_INDEX		0xFFFFFFFF
+
+struct client_data {
+	/** ARP data of single client */
+	struct ether_addr app_mac;
+	/**< MAC address of application running DPDK */
+	uint32_t app_ip;
+	/**< IP address of application running DPDK */
+	struct ether_addr cli_mac;
+	/**< Client MAC address */
+	uint32_t cli_ip;
+	/**< Client IP address */
+
+	uint8_t slave_idx;
+	/**< Index of slave on which we connect with that client */
+	uint8_t in_use;
+	/**< Flag indicating if entry in client table is currently used */
+	uint8_t ntt;
+	/**< Flag indicating if we need to send update to this client on next tx */
+
+	struct vlan_hdr vlan[2];
+	/**< Content of vlan headers */
+	uint8_t vlan_count;
+	/**< Number of nested vlan headers */
+};
+
+struct mode_alb_private {
+	struct client_data client_table[ALB_HASH_TABLE_SIZE];
+	/**< Hash table storing ARP data of every client connected */
+	struct rte_mempool *mempool;
+	/**< Mempool for creating ARP update packets */
+	uint8_t ntt;
+	/**< Flag indicating if we need to send update to any client on next tx */
+	uint32_t last_slave;
+	/**< Index of last used slave in client table */
+	rte_spinlock_t lock;
+};
+
+/**
+ * ALB mode initialization.
+ *
+ * @param bond_dev		Pointer to bonding device.
+ *
+ * @return
+ * Error code - 0 on success.
+ */
+int
+bond_mode_alb_enable(struct rte_eth_dev *bond_dev);
+
+/**
+ * Function handles ARP packet reception. If received ARP request, it is
+ * forwarded to application without changes. If it is ARP reply, client table
+ * is updated.
+ *
+ * @param eth_h			ETH header of received packet.
+ * @param offset		Vlan header offset.
+ * @param internals		Bonding data.
+ */
+void
+bond_mode_alb_arp_recv(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals);
+
+/**
+ * Function handles ARP packet transmission. It also decides on which slave
+ * send that packet. If packet is ARP Request, it is send on primary slave.
+ * If it is ARP Reply, it is send on slave stored in client table for that
+ * connection. On Reply function also updates data in client table.
+ *
+ * @param eth_h			ETH header of transmitted packet.
+ * @param offset		Vlan header offset.
+ * @param internals		Bonding data.
+ *
+ * @return
+ * Index of slave on which packet should be sent.
+ */
+uint8_t
+bond_mode_alb_arp_xmit(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals);
+
+/**
+ * Function fills packet with ARP data from client_info.
+ *
+ * @param client_info	Data of client to which packet is sent.
+ * @param pkt			Pointer to packet which is sent.
+ * @param internals		Bonding data.
+ *
+ * @return
+ * Index of slawe on which packet should be sent.
+ */
+uint8_t
+bond_mode_alb_arp_upd(struct client_data *client_info,
+		struct rte_mbuf *pkt, struct bond_dev_private *internals);
+
+/**
+ * Function updates slave indexes of active connections.
+ *
+ * @param bond_dev		Pointer to bonded device struct.
+ */
+void
+bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev);
+
+#endif /* RTE_ETH_BOND_ALB_H_ */
diff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c
index 4ab3267..cbfd185 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_api.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c
@@ -111,15 +111,27 @@ void
 activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 {
 	struct bond_dev_private *internals = eth_dev->data->dev_private;
+	uint8_t active_count = internals->active_slave_count;
 
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_activate_slave(eth_dev, port_id);
 
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+			|| internals->mode == BONDING_MODE_ALB) {
+
+		internals->tlb_slaves_order[active_count] = port_id;
+	}
+
 	RTE_VERIFY(internals->active_slave_count <
 			(RTE_DIM(internals->active_slaves) - 1));
 
 	internals->active_slaves[internals->active_slave_count] = port_id;
 	internals->active_slave_count++;
+
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)
+		bond_tlb_activate_slave(internals);
+	if (internals->mode == BONDING_MODE_ALB)
+		bond_mode_alb_client_list_upd(eth_dev);
 }
 
 void
@@ -132,7 +144,9 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (internals->mode == BONDING_MODE_8023AD) {
 		bond_mode_8023ad_stop(eth_dev);
 		bond_mode_8023ad_deactivate_slave(eth_dev, port_id);
-	}
+	} else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+			|| internals->mode == BONDING_MODE_ALB)
+		bond_tlb_disable(internals);
 
 	slave_pos = find_slave_by_id(internals->active_slaves, active_count,
 			port_id);
@@ -150,8 +164,16 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	RTE_VERIFY(active_count < RTE_DIM(internals->active_slaves));
 	internals->active_slave_count = active_count;
 
-	if (eth_dev->data->dev_started && internals->mode == BONDING_MODE_8023AD)
-		bond_mode_8023ad_start(eth_dev);
+	if (eth_dev->data->dev_started) {
+	   if (internals->mode == BONDING_MODE_8023AD) {
+			   bond_mode_8023ad_start(eth_dev);
+	   } else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {
+			   bond_tlb_enable(internals);
+	   } else if (internals->mode == BONDING_MODE_ALB) {
+			   bond_tlb_enable(internals);
+			   bond_mode_alb_client_list_upd(eth_dev);
+	   }
+	}
 }
 
 uint8_t
diff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c
index ca4de38..a3f7f55 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_args.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c
@@ -175,6 +175,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,
 #endif
 	case BONDING_MODE_8023AD:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 		return 0;
 	default:
 		RTE_BOND_LOG(ERR, "Invalid slave mode value (%s) specified", value);
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index 09b0f30..40e4ccb 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -56,6 +56,26 @@
 /* Table for statistics in mode 5 TLB */
 static uint64_t tlb_last_obytets[RTE_MAX_ETHPORTS];
 
+static inline size_t
+get_vlan_offset(struct ether_hdr *eth_hdr, uint16_t *proto)
+{
+	size_t vlan_offset = 0;
+
+	if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
+		vlan_offset = sizeof(struct vlan_hdr);
+		*proto = vlan_hdr->eth_proto;
+
+		if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+			vlan_hdr = vlan_hdr + 1;
+
+			*proto = vlan_hdr->eth_proto;
+			vlan_offset += sizeof(struct vlan_hdr);
+		}
+	}
+	return vlan_offset;
+}
+
 static uint16_t
 bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
@@ -173,6 +193,34 @@ bond_ethdev_rx_burst_8023ad(void *queue, struct rte_mbuf **bufs,
 }
 
 static uint16_t
+bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;
+	struct bond_dev_private *internals = bd_tx_q->dev_private;
+
+	struct ether_hdr *eth_h;
+
+	uint16_t ether_type, offset;
+	uint16_t nb_recv_pkts;
+
+	int i;
+
+	nb_recv_pkts = bond_ethdev_rx_burst(queue, bufs, nb_pkts);
+
+	for (i = 0; i < nb_recv_pkts; i++) {
+		eth_h = rte_pktmbuf_mtod(bufs[i], struct ether_hdr *);
+		ether_type = eth_h->ether_type;
+		offset = get_vlan_offset(eth_h, &ether_type);
+
+		if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+			bond_mode_alb_arp_recv(eth_h, offset, internals);
+		}
+	}
+
+	return nb_recv_pkts;
+}
+
+static uint16_t
 bond_ethdev_tx_burst_round_robin(void *queue, struct rte_mbuf **bufs,
 		uint16_t nb_pkts)
 {
@@ -281,26 +329,6 @@ ipv6_hash(struct ipv6_hdr *ipv6_hdr)
 			(word_src_addr[3] ^ word_dst_addr[3]);
 }
 
-static inline size_t
-get_vlan_offset(struct ether_hdr *eth_hdr, uint16_t *proto)
-{
-	size_t vlan_offset = 0;
-
-	if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
-		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
-		vlan_offset = sizeof(struct vlan_hdr);
-		*proto = vlan_hdr->eth_proto;
-
-		if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
-			vlan_hdr = vlan_hdr + 1;
-
-			*proto = vlan_hdr->eth_proto;
-			vlan_offset += sizeof(struct vlan_hdr);
-		}
-	}
-	return vlan_offset;
-}
-
 uint16_t
 xmit_l2_hash(const struct rte_mbuf *buf, uint8_t slave_count)
 {
@@ -396,6 +424,15 @@ struct bwg_slave {
 	uint8_t slave;
 };
 
+void
+bond_tlb_activate_slave(struct bond_dev_private *internals) {
+	int i;
+
+	for (i = 0; i < internals->active_slave_count; i++) {
+		tlb_last_obytets[internals->active_slaves[i]] = 0;
+	}
+}
+
 static int
 bandwidth_cmp(const void *a, const void *b)
 {
@@ -426,7 +463,7 @@ bandwidth_left(int port_id, uint64_t load, uint8_t update_idx,
 	uint64_t link_bwg = link_status.link_speed * 1000000ULL / 8;
 	if (link_bwg == 0)
 		return;
-	link_bwg = (link_bwg * (update_idx+1) * REORDER_PERIOD_MS);
+	link_bwg = link_bwg * (update_idx+1) * REORDER_PERIOD_MS;
 	bwg_slave->bwg_left_int = (link_bwg - 1000*load) / link_bwg;
 	bwg_slave->bwg_left_remainder = (link_bwg - 1000*load) % link_bwg;
 }
@@ -457,8 +494,9 @@ bond_ethdev_update_tlb_slave_cb(void *arg)
 				internals->slave_update_idx, &bwg_array[i]);
 		bwg_array[i].slave = slave_id;
 
-		if (update_stats)
+		if (update_stats) {
 			tlb_last_obytets[slave_id] = slave_stats.obytes;
+		}
 	}
 
 	if (update_stats == 1)
@@ -467,7 +505,7 @@ bond_ethdev_update_tlb_slave_cb(void *arg)
 	slave_count = i;
 	qsort(bwg_array, slave_count, sizeof(bwg_array[0]), bandwidth_cmp);
 	for (i = 0; i < slave_count; i++)
-		internals->active_slaves[i] = bwg_array[i].slave;
+		internals->tlb_slaves_order[i] = bwg_array[i].slave;
 
 	rte_eal_alarm_set(REORDER_PERIOD_MS * 1000, bond_ethdev_update_tlb_slave_cb,
 			(struct bond_dev_private *)internals);
@@ -494,8 +532,8 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	if (num_of_slaves < 1)
 		return num_tx_total;
 
-	memcpy(slaves, internals->active_slaves,
-				sizeof(internals->active_slaves[0]) * num_of_slaves);
+	memcpy(slaves, internals->tlb_slaves_order,
+				sizeof(internals->tlb_slaves_order[0]) * num_of_slaves);
 
 
 	ether_addr_copy(primary_port->data->mac_addrs, &primary_slave_addr);
@@ -506,9 +544,7 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	}
 
 	for (i = 0; i < num_of_slaves; i++) {
-		ether_addr_copy(&internals->slaves[slaves[i]].persisted_mac_addr,
-				&active_slave_addr);
-
+		rte_eth_macaddr_get(slaves[i], &active_slave_addr);
 		for (j = num_tx_total; j < nb_pkts; j++) {
 			if (j + 3 < nb_pkts)
 				rte_prefetch0(rte_pktmbuf_mtod(bufs[j+3], void*));
@@ -528,6 +564,147 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	return num_tx_total;
 }
 
+void
+bond_tlb_disable(struct bond_dev_private *internals)
+{
+       rte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, internals);
+}
+
+void
+bond_tlb_enable(struct bond_dev_private *internals)
+{
+       bond_ethdev_update_tlb_slave_cb(internals);
+}
+
+static uint16_t
+bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;
+	struct bond_dev_private *internals = bd_tx_q->dev_private;
+
+	struct ether_hdr *eth_h;
+	uint16_t ether_type, offset;
+
+	struct client_data *client_info;
+
+	/*
+	 * We create transmit buffers for every slave and one additional to send
+	 * through tlb. In worst case every packet will be send on one port.
+	 */
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS + 1][nb_pkts];
+	uint16_t slave_bufs_pkts[RTE_MAX_ETHPORTS + 1] = { 0 };
+
+	/*
+	 * We create separate transmit buffers for update packets as they wont be
+	 * counted in num_tx_total.
+	 */
+	struct rte_mbuf *update_bufs[RTE_MAX_ETHPORTS][ALB_HASH_TABLE_SIZE];
+	uint16_t update_bufs_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	struct rte_mbuf *upd_pkt;
+	size_t pkt_size;
+
+	uint16_t num_send, num_not_send = 0;
+	uint16_t num_tx_total = 0;
+	uint8_t slave_idx;
+
+	int i, j;
+
+	/* Search tx buffer for ARP packets and forward them to alb */
+	for (i = 0; i < nb_pkts; i++) {
+		eth_h = rte_pktmbuf_mtod(bufs[i], struct ether_hdr *);
+		ether_type = eth_h->ether_type;
+		offset = get_vlan_offset(eth_h, &ether_type);
+
+		if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+			slave_idx = bond_mode_alb_arp_xmit(eth_h, offset, internals);
+
+			/* Change src mac in eth header */
+			rte_eth_macaddr_get(slave_idx, &eth_h->s_addr);
+
+			/* Add packet to slave tx buffer */
+			slave_bufs[slave_idx][slave_bufs_pkts[slave_idx]] = bufs[i];
+			slave_bufs_pkts[slave_idx]++;
+		} else {
+			/* If packet is not ARP, send it with TLB policy */
+			slave_bufs[RTE_MAX_ETHPORTS][slave_bufs_pkts[RTE_MAX_ETHPORTS]] =
+					bufs[i];
+			slave_bufs_pkts[RTE_MAX_ETHPORTS]++;
+		}
+	}
+
+	/* Update connected client ARP tables */
+	if (internals->mode6.ntt) {
+		for (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {
+			client_info = &internals->mode6.client_table[i];
+
+			if (client_info->in_use) {
+				/* Allocate new packet to send ARP update on current slave */
+				upd_pkt = rte_pktmbuf_alloc(internals->mode6.mempool);
+				if (upd_pkt == NULL) {
+					RTE_LOG(ERR, PMD, "Failed to allocate ARP packet from pool\n");
+					continue;
+				}
+				pkt_size = sizeof(struct ether_hdr) + sizeof(struct arp_hdr)
+						+ client_info->vlan_count * sizeof(struct vlan_hdr);
+				upd_pkt->data_len = pkt_size;
+				upd_pkt->pkt_len = pkt_size;
+
+				slave_idx = bond_mode_alb_arp_upd(client_info, upd_pkt,
+						internals);
+
+				/* Add packet to update tx buffer */
+				update_bufs[slave_idx][update_bufs_pkts[slave_idx]] = upd_pkt;
+				update_bufs_pkts[slave_idx]++;
+			}
+		}
+		internals->mode6.ntt = 0;
+	}
+
+	/* Send ARP packets on proper slaves */
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (slave_bufs_pkts[i] > 0) {
+			num_send = rte_eth_tx_burst(i, bd_tx_q->queue_id,
+					slave_bufs[i], slave_bufs_pkts[i]);
+			for (j = 0; j < slave_bufs_pkts[i] - num_send; j++) {
+				bufs[nb_pkts - 1 - num_not_send - j] =
+						slave_bufs[i][nb_pkts - 1 - j];
+			}
+
+			num_tx_total += num_send;
+			num_not_send += slave_bufs_pkts[i] - num_send;
+		}
+	}
+
+	/* Send update packets on proper slaves */
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (update_bufs_pkts[i] > 0) {
+			num_send = rte_eth_tx_burst(i, bd_tx_q->queue_id, update_bufs[i],
+					update_bufs_pkts[i]);
+			for (j = num_send; j < update_bufs_pkts[i]; j++) {
+				rte_pktmbuf_free(update_bufs[i][j]);
+			}
+		}
+	}
+
+	/* Send non-ARP packets using tlb policy */
+	if (slave_bufs_pkts[RTE_MAX_ETHPORTS] > 0) {
+		num_send = bond_ethdev_tx_burst_tlb(queue,
+				slave_bufs[RTE_MAX_ETHPORTS],
+				slave_bufs_pkts[RTE_MAX_ETHPORTS]);
+
+		for (j = 0; j < slave_bufs_pkts[RTE_MAX_ETHPORTS]; j++) {
+			bufs[nb_pkts - 1 - num_not_send - j] =
+					slave_bufs[RTE_MAX_ETHPORTS][nb_pkts - 1 - j];
+		}
+
+		num_tx_total += num_send;
+		num_not_send += slave_bufs_pkts[RTE_MAX_ETHPORTS] - num_send;
+	}
+
+	return num_tx_total;
+}
+
 static uint16_t
 bond_ethdev_tx_burst_balance(void *queue, struct rte_mbuf **bufs,
 		uint16_t nb_pkts)
@@ -856,6 +1033,7 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
 		break;
 	case BONDING_MODE_ACTIVE_BACKUP:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 	default:
 		for (i = 0; i < internals->slave_count; i++) {
 			if (internals->slaves[i].port_id ==
@@ -921,6 +1099,13 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
 		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb;
 		eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup;
 		break;
+	case BONDING_MODE_ALB:
+		if (bond_mode_alb_enable(eth_dev) != 0)
+			return -1;
+
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_alb;
+		eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_alb;
+		break;
 	default:
 		return -1;
 	}
@@ -1136,8 +1321,9 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_start(eth_dev);
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)
-		bond_ethdev_update_tlb_slave_cb(internals);
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+			internals->mode == BONDING_MODE_ALB)
+		bond_tlb_enable(internals);
 
 	return 0;
 }
@@ -1168,8 +1354,11 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)
 		}
 	}
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {
-		rte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, internals);
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+			internals->mode == BONDING_MODE_ALB) {
+		bond_tlb_disable(internals);
+		for (i = 0; i < internals->active_slave_count; i++)
+			tlb_last_obytets[internals->active_slaves[i]] = 0;
 	}
 
 	internals->active_slave_count = 0;
@@ -1366,8 +1555,12 @@ bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 {
 	struct bond_dev_private *internals = dev->data->dev_private;
 	struct rte_eth_stats slave_stats;
+
 	int i;
 
+	/* clear bonded stats before populating from slaves */
+	memset(stats, 0, sizeof(*stats));
+
 	for (i = 0; i < internals->slave_count; i++) {
 		rte_eth_stats_get(internals->slaves[i].port_id, &slave_stats);
 
@@ -1422,6 +1615,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_enable(internals->current_primary_port);
 	}
@@ -1451,6 +1645,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_disable(internals->current_primary_port);
 	}
diff --git a/lib/librte_pmd_bond/rte_eth_bond_private.h b/lib/librte_pmd_bond/rte_eth_bond_private.h
index 3da5a9e..bef1e81 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_private.h
+++ b/lib/librte_pmd_bond/rte_eth_bond_private.h
@@ -39,6 +39,7 @@
 
 #include "rte_eth_bond.h"
 #include "rte_eth_bond_8023ad_private.h"
+#include "rte_eth_bond_alb.h"
 
 #define PMD_BOND_SLAVE_PORT_KVARG			("slave")
 #define PMD_BOND_PRIMARY_SLAVE_KVARG		("primary")
@@ -148,6 +149,8 @@ struct bond_dev_private {
 	/**< Arary of bonded slaves details */
 
 	struct mode8023ad_private mode4;
+	uint8_t tlb_slaves_order[RTE_MAX_ETHPORTS]; /* TLB active slaves send order */
+	struct mode_alb_private mode6;
 
 	uint32_t rx_offload_capa;            /** Rx offload capability */
 	uint32_t tx_offload_capa;            /** Tx offload capability */
@@ -272,4 +275,13 @@ int
 bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,
 		const char *value, void *extra_args);
 
+void
+bond_tlb_disable(struct bond_dev_private *internals);
+
+void
+bond_tlb_enable(struct bond_dev_private *internals);
+
+void
+bond_tlb_activate_slave(struct bond_dev_private *internals);
+
 #endif
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v2 3/6] bond: add debug info for mode 6 link bonding
  2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 2/6] bond: add link bonding mode 6 implementation Michal Jastrzebski
@ 2015-02-13 15:16 ` Michal Jastrzebski
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-13 15:16 UTC (permalink / raw)
  To: dev

v2 changes
- add IPv4 RX/TX information
- add mode6_debug(..) function  

This patch add some debug information when using link bonding mode 6.
It prints basic information about ARP packets on RX and TX (MAC, ip,
packet number, arp packet type).
If CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB == y.
If CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1 is enabled instead of previous
one, use show command to see IPv4 balancing from clients.

Signed-off-by: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
---
 config/common_linuxapp                 |    3 +-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c |  199 +++++++++++++++++++++++++++++++-
 2 files changed, 198 insertions(+), 4 deletions(-)

diff --git a/config/common_linuxapp b/config/common_linuxapp
index d428f84..7c54edf 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -220,7 +220,8 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=n
 # Compile link bonding PMD library
 #
 CONFIG_RTE_LIBRTE_PMD_BOND=y
-
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
 #
 # Compile software PMD backed by AF_PACKET sockets (Linux only)
 #
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index 40e4ccb..f469b5c 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -192,17 +192,185 @@ bond_ethdev_rx_burst_8023ad(void *queue, struct rte_mbuf **bufs,
 	return num_rx_total;
 }
 
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+uint32_t burstnumberRX;
+uint32_t burstnumberTX;
+
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+
+static void
+arp_op_name(uint16_t arp_op, char *buf)
+{
+	switch (arp_op) {
+	case ARP_OP_REQUEST:
+		snprintf(buf, sizeof("ARP Request"), "%s", "ARP Request");
+		return;
+	case ARP_OP_REPLY:
+		snprintf(buf, sizeof("ARP Reply"), "%s", "ARP Reply");
+		return;
+	case ARP_OP_REVREQUEST:
+		snprintf(buf, sizeof("Reverse ARP Request"), "%s", "Reverse ARP Request");
+		return;
+	case ARP_OP_REVREPLY:
+		snprintf(buf, sizeof("Reverse ARP Reply"), "%s", "Reverse ARP Reply");
+		return;
+	case ARP_OP_INVREQUEST:
+		snprintf(buf, sizeof("Peer Identify Request"), "%s", "Peer Identify Request");
+		return;
+	case ARP_OP_INVREPLY:
+		snprintf(buf, sizeof("Peer Identify Reply"), "%s", "Peer Identify Reply");
+		return;
+	default:
+		break;
+	}
+	snprintf(buf, sizeof("Unknown"), "%s", "Unknown");
+	return;
+}
+#endif
+#define MaxIPv4String	16
+static void
+ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf, uint8_t buf_size)
+{
+	uint32_t ipv4_addr;
+
+	ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr);
+	snprintf(buf, buf_size, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF,
+		(ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF,
+		ipv4_addr & 0xFF);
+}
+
+#define MAX_CLIENTS_NUMBER	128
+uint8_t active_clients;
+struct client_stats_t {
+	uint8_t port;
+	uint32_t ipv4_addr;
+	uint32_t ipv4_rx_packets;
+	uint32_t ipv4_tx_packets;
+};
+struct client_stats_t client_stats[MAX_CLIENTS_NUMBER];
+
+static void
+update_client_stats(uint32_t addr, uint8_t port, uint32_t *TXorRXindicator)
+{
+	int i = 0;
+	for (; i < MAX_CLIENTS_NUMBER; i++)	{
+		if ((client_stats[i].ipv4_addr == addr) && (client_stats[i].port == port))	{
+			/* Just update RX packets number for this client */
+			if (TXorRXindicator == &burstnumberRX)	{
+				client_stats[i].ipv4_rx_packets++;
+			} else {
+				client_stats[i].ipv4_tx_packets++;
+			}
+			return;
+		}
+	}
+			/* We have a new client. Insert him to the table, and increment stats */
+	if (TXorRXindicator == &burstnumberRX)	{
+		client_stats[active_clients].ipv4_rx_packets++;
+	} else {
+		client_stats[active_clients].ipv4_tx_packets++;
+	}
+	client_stats[active_clients].ipv4_addr = addr;
+	client_stats[active_clients].port = port;
+	active_clients++;
+
+	return;
+}
+
+void print_client_stats(void);
+void print_client_stats(void)
+{
+	int i = 0;
+	char buf[MaxIPv4String];
+
+	for (; i < active_clients; i++)	{
+		ipv4_addr_to_dot(client_stats[i].ipv4_addr, buf, MaxIPv4String);
+		printf("port:%d client:%s RX:%d TX:%d\n", \
+				client_stats[i].port, \
+				buf, \
+				client_stats[i].ipv4_rx_packets, \
+				client_stats[i].ipv4_tx_packets);
+	}
+}
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+#define MODE6_DEBUG(info, src_ip, dst_ip, eth_h, arp_op, port, burstnumber)	\
+		RTE_LOG(DEBUG, PMD, \
+		"%s " \
+		"port:%d " \
+		"SrcMAC:%02X:%02X:%02X:%02X:%02X:%02X " \
+		"SrcIP:%s " \
+		"DstMAC:%02X:%02X:%02X:%02X:%02X:%02X " \
+		"DstIP:%s " \
+		"%s " \
+		"%d\n", \
+		info, \
+		port, \
+		eth_h->s_addr.addr_bytes[0], \
+		eth_h->s_addr.addr_bytes[1], \
+		eth_h->s_addr.addr_bytes[2], \
+		eth_h->s_addr.addr_bytes[3], \
+		eth_h->s_addr.addr_bytes[4], \
+		eth_h->s_addr.addr_bytes[5], \
+		src_ip, \
+		eth_h->d_addr.addr_bytes[0], \
+		eth_h->d_addr.addr_bytes[1], \
+		eth_h->d_addr.addr_bytes[2], \
+		eth_h->d_addr.addr_bytes[3], \
+		eth_h->d_addr.addr_bytes[4], \
+		eth_h->d_addr.addr_bytes[5], \
+		dst_ip, \
+		arp_op, \
+		++burstnumber)
+#endif
+
+static void
+mode6_debug(const char __attribute__((unused)) *info, struct ether_hdr *eth_h, uint8_t port, uint32_t __attribute__((unused)) *burstnumber)
+{
+	struct ipv4_hdr *ipv4_h;
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+	struct arp_hdr *arp_h;
+	char dst_ip[16];
+	char ArpOp[24];
+	char buf[16];
+#endif
+	char src_ip[16];
+
+	uint16_t ether_type = eth_h->ether_type;
+	uint16_t offset = get_vlan_offset(eth_h, &ether_type);
+
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+	snprintf(buf, 16, "%s", info);
+#endif
+
+	if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		ipv4_h = (struct ipv4_hdr *)((char *)(eth_h + 1) + offset);
+		ipv4_addr_to_dot(ipv4_h->src_addr, src_ip, MaxIPv4String);
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+		ipv4_addr_to_dot(ipv4_h->dst_addr, dst_ip, MaxIPv4String);
+		MODE6_DEBUG(buf, src_ip, dst_ip, eth_h, "", port, *burstnumber);
+#endif
+		update_client_stats(ipv4_h->src_addr, port, burstnumber);
+	}
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+	else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+		arp_h = (struct arp_hdr *)((char *)(eth_h + 1) + offset);
+		ipv4_addr_to_dot(arp_h->arp_data.arp_sip, src_ip, MaxIPv4String);
+		ipv4_addr_to_dot(arp_h->arp_data.arp_tip, dst_ip, MaxIPv4String);
+		arp_op_name(rte_be_to_cpu_16(arp_h->arp_op), ArpOp);
+		MODE6_DEBUG(buf, src_ip, dst_ip, eth_h, ArpOp, port, *burstnumber);
+	}
+#endif
+}
+#endif
+
 static uint16_t
 bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
 	struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;
 	struct bond_dev_private *internals = bd_tx_q->dev_private;
-
 	struct ether_hdr *eth_h;
-
 	uint16_t ether_type, offset;
 	uint16_t nb_recv_pkts;
-
 	int i;
 
 	nb_recv_pkts = bond_ethdev_rx_burst(queue, bufs, nb_pkts);
@@ -213,8 +381,16 @@ bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		offset = get_vlan_offset(eth_h, &ether_type);
 
 		if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+		mode6_debug("RX ARP:", eth_h, bufs[i]->port, &burstnumberRX);
+#endif
 			bond_mode_alb_arp_recv(eth_h, offset, internals);
 		}
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+		else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+			mode6_debug("RX IPv4:", eth_h, bufs[i]->port, &burstnumberRX);
+		}
+#endif
 	}
 
 	return nb_recv_pkts;
@@ -552,6 +728,9 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			ether_hdr = rte_pktmbuf_mtod(bufs[j], struct ether_hdr *);
 			if (is_same_ether_addr(&ether_hdr->s_addr, &primary_slave_addr))
 				ether_addr_copy(&active_slave_addr, &ether_hdr->s_addr);
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+					mode6_debug("TX IPv4:", ether_hdr, slaves[i], &burstnumberTX);
+#endif
 		}
 
 		num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
@@ -673,6 +852,14 @@ bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 
 			num_tx_total += num_send;
 			num_not_send += slave_bufs_pkts[i] - num_send;
+
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+	/* Print TX stats including update packets */
+			for (j = 0; j < slave_bufs_pkts[i]; j++) {
+				eth_h = rte_pktmbuf_mtod(slave_bufs[i][j], struct ether_hdr *);
+				mode6_debug("TX ARP:", eth_h, i, &burstnumberTX);
+			}
+#endif
 		}
 	}
 
@@ -684,6 +871,12 @@ bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			for (j = num_send; j < update_bufs_pkts[i]; j++) {
 				rte_pktmbuf_free(update_bufs[i][j]);
 			}
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+			for (j = 0; j < update_bufs_pkts[i]; j++) {
+				eth_h = rte_pktmbuf_mtod(update_bufs[i][j], struct ether_hdr *);
+				mode6_debug("TX ARPupd:", eth_h, i, &burstnumberTX);
+			}
+#endif
 		}
 	}
 
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v2 4/6] bond: add example application for link bonding mode 6
  2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                   ` (2 preceding siblings ...)
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 3/6] bond: add debug info for mode 6 link bonding Michal Jastrzebski
@ 2015-02-13 15:16 ` Michal Jastrzebski
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 5/6] bond: modify TLB unit tests Michal Jastrzebski
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-13 15:16 UTC (permalink / raw)
  To: dev

v2 changes
- remove count parameter from send command
- fixed quit command to use cmdline_quit(cl)
- add echo function - all IPv4 packets will be retransmitted. Bonding
driver will use TLB policy - this will show how TX works in mode 6
- remove unused structures rx_conf_default and tx_conf_default
- add VLAN support
- remove unnecessary comments
- nodify show command in term of printing DEBUG informations

This patch contains an example for link bonding mode 6.
It interact with user by a command prompt. Available commands are:
Start - starts ARP_thread which respond to ARP_requests and sends
ARP_updates (this
Is enabled by default after startup),
Stop  -stops ARP_thread,
Send count ip - send count ARP requests for IP,
Show - prints basic bond information, like IPv4 statistics from clients
Help,
Quit.
The best way to test mode 6 is to use this example together with
previous patch:
[PATCH 3/4] bond: add debug info for mode 6 link bonding.
Connect clients thru switch to bonding machine and send:
arping -c 1 bond_ip or
generate IPv4 traffic to bond_ip (IPv4 traffic from different clients
should be then balanced on slaves in round robin manner).

Signed-off-by: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
Signed-off-by: Maciej Gajdzica  <maciejx.t.gajdzica@intel.com>
---
 examples/bond/Makefile |   57 ++++
 examples/bond/main.c   |  792 ++++++++++++++++++++++++++++++++++++++++++++++++
 examples/bond/main.h   |   46 +++
 3 files changed, 895 insertions(+)
 create mode 100644 examples/bond/Makefile
 create mode 100644 examples/bond/main.c
 create mode 100644 examples/bond/main.h

diff --git a/examples/bond/Makefile b/examples/bond/Makefile
new file mode 100644
index 0000000..9262249
--- /dev/null
+++ b/examples/bond/Makefile
@@ -0,0 +1,57 @@
+#   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.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = bond_app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += $(WERROR_FLAGS)
+
+# workaround for a gcc bug with noreturn attribute
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
+CFLAGS_main.o += -Wno-return-type
+endif
+
+CFLAGS += -O3
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/bond/main.c b/examples/bond/main.c
new file mode 100644
index 0000000..550aec1
--- /dev/null
+++ b/examples/bond/main.c
@@ -0,0 +1,792 @@
+/*-
+ *   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 <stdint.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <termios.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_log.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_memcpy.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_arp.h>
+#include <rte_spinlock.h>
+
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "main.h"
+
+#include <rte_devargs.h>
+
+
+#include "rte_byteorder.h"
+#include "rte_cpuflags.h"
+#include "rte_eth_bond.h"
+
+#define RTE_LOGTYPE_DCB RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   (1024*8)
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100      /* TX drain every ~100us */
+#define BURST_RX_INTERVAL_NS (10) /* RX poll interval ~100ns */
+
+/*
+ * RX and TX Prefetch, Host, and Write-back threshold values should be
+ * carefully set for optimal performance. Consult the network
+ * controller's datasheet and supporting DPDK documentation for guidance
+ * on how these parameters should be set.
+ */
+#define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */
+#define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */
+#define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */
+#define RX_FTHRESH (MAX_PKT_BURST * 2)/**< Default values of RX free threshold reg. */
+
+/*
+ * These default values are optimized for use with the Intel(R) 82599 10 GbE
+ * Controller and the DPDK ixgbe PMD. Consider using other values for other
+ * network controllers and/or network drivers.
+ */
+#define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */
+#define TX_HTHRESH 0  /**< Default values of TX host threshold reg. */
+#define TX_WTHRESH 0  /**< Default values of TX write-back threshold reg. */
+
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_RX_DESC_DEFAULT 128
+#define RTE_TX_DESC_DEFAULT 512
+
+#define BOND_IP_1	7
+#define BOND_IP_2	0
+#define BOND_IP_3	0
+#define BOND_IP_4	10
+
+/* not defined under linux */
+#ifndef NIPQUAD
+#define NIPQUAD_FMT "%u.%u.%u.%u"
+#define NIPQUAD(addr)				\
+	(unsigned)((unsigned char *)&addr)[0],	\
+	(unsigned)((unsigned char *)&addr)[1],	\
+	(unsigned)((unsigned char *)&addr)[2],	\
+	(unsigned)((unsigned char *)&addr)[3]
+#endif
+
+#define MAX_PORTS	4
+#define PRINT_MAC(addr)		printf("%02"PRIx8":%02"PRIx8":%02"PRIx8 \
+		":%02"PRIx8":%02"PRIx8":%02"PRIx8,	\
+		addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2], \
+		addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5])
+
+uint8_t slaves[RTE_MAX_ETHPORTS];
+uint8_t slaves_count;
+
+static uint8_t BOND_PORT = 0xff;
+
+static struct rte_mempool *mbuf_pool;
+
+static struct rte_eth_conf port_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 */
+	},
+	.rx_adv_conf = {
+		.rss_conf = {
+			.rss_key = NULL,
+			.rss_hf = ETH_RSS_IP,
+		},
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static void
+slave_port_init(uint8_t portid, struct rte_mempool *mbuf_pool)
+{
+	int retval;
+
+	if (portid >= rte_eth_dev_count())
+		rte_exit(EXIT_FAILURE, "Invalid port\n");
+
+	retval = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+	if (retval != 0)
+		rte_exit(EXIT_FAILURE, "port %u: configuration failed (res=%d)\n", \
+				portid, retval);
+
+	/* RX setup */
+	retval = rte_eth_rx_queue_setup(portid, 0, RTE_RX_DESC_DEFAULT,
+					rte_eth_dev_socket_id(portid), NULL,
+					mbuf_pool);
+	if (retval < 0)
+		rte_exit(retval, " port %u: RX queue 0 setup failed (res=%d)", \
+				portid, retval);
+
+	/* TX setup */
+	retval = rte_eth_tx_queue_setup(portid, 0, RTE_TX_DESC_DEFAULT,
+				rte_eth_dev_socket_id(portid), NULL);
+
+	if (retval < 0)
+		rte_exit(retval, "port %u: TX queue 0 setup failed (res=%d)", \
+				portid, retval);
+
+	retval  = rte_eth_dev_start(portid);
+	if (retval < 0)
+		rte_exit(retval, \
+				"Start port %d failed (res=%d)", \
+				portid, retval);
+
+	struct ether_addr addr;
+	rte_eth_macaddr_get(portid, &addr);
+	printf("Port %u MAC: ", (unsigned)portid);
+	PRINT_MAC(addr);
+	printf("\n");
+}
+
+static void
+bond_port_init(struct rte_mempool *mbuf_pool)
+{
+	int retval;
+	uint8_t i;
+
+	retval = rte_eth_bond_create("bond0", BONDING_MODE_ALB, 0 /*SOCKET_ID_ANY*/);
+	if (retval < 0)
+		rte_exit(EXIT_FAILURE, \
+				"Faled to create bond port\n");
+
+	BOND_PORT = (uint8_t)retval;
+
+	retval = rte_eth_dev_configure(BOND_PORT, 1, 1, &port_conf);
+	if (retval != 0)
+		rte_exit(EXIT_FAILURE, "port %u: configuration failed (res=%d)\n", \
+				BOND_PORT, retval);
+
+	/* RX setup */
+	retval = rte_eth_rx_queue_setup(BOND_PORT, 0, RTE_RX_DESC_DEFAULT,
+					rte_eth_dev_socket_id(BOND_PORT), NULL,
+					mbuf_pool);
+	if (retval < 0)
+		rte_exit(retval, " port %u: RX queue 0 setup failed (res=%d)", \
+				BOND_PORT, retval);
+
+	/* TX setup */
+	retval = rte_eth_tx_queue_setup(BOND_PORT, 0, RTE_TX_DESC_DEFAULT,
+				rte_eth_dev_socket_id(BOND_PORT), NULL);
+
+	if (retval < 0)
+		rte_exit(retval, "port %u: TX queue 0 setup failed (res=%d)", \
+				BOND_PORT, retval);
+
+	for (i = 0; i < slaves_count; i++) {
+		if (rte_eth_bond_slave_add(BOND_PORT, slaves[i]) == -1)
+			rte_exit(-1, "Oooops! adding slave (%u) to bond (%u) failed!\n", \
+					slaves[i], BOND_PORT);
+
+	}
+
+	retval  = rte_eth_dev_start(BOND_PORT);
+	if (retval < 0)
+		rte_exit(retval, "Start port %d failed (res=%d)", BOND_PORT, retval);
+
+	rte_eth_promiscuous_enable(BOND_PORT);
+
+	struct ether_addr addr;
+	rte_eth_macaddr_get(BOND_PORT, &addr);
+	printf("Port %u MAC: ", (unsigned)BOND_PORT);
+		PRINT_MAC(addr);
+		printf("\n");
+}
+
+static inline size_t
+get_vlan_offset(struct ether_hdr *eth_hdr, uint16_t *proto)
+{
+	size_t vlan_offset = 0;
+
+	if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
+		vlan_offset = sizeof(struct vlan_hdr);
+		*proto = vlan_hdr->eth_proto;
+
+		if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+			vlan_hdr = vlan_hdr + 1;
+
+			*proto = vlan_hdr->eth_proto;
+			vlan_offset += sizeof(struct vlan_hdr);
+		}
+	}
+	return vlan_offset;
+}
+
+struct global_flag_stru_t {
+	int LcoreMainIsRunning;
+	int LcoreMainCore;
+	uint32_t port_packets[4];
+	rte_spinlock_t lock;
+};
+struct global_flag_stru_t global_flag_stru;
+struct global_flag_stru_t *global_flag_stru_p = &global_flag_stru;
+
+/*
+ * Main thread that does the work, reading from INPUT_PORT
+ * and writing to OUTPUT_PORT
+ */
+static int lcore_main(__attribute__((unused)) void *arg1)
+{
+	struct rte_mbuf *pkts[MAX_PKT_BURST] __rte_cache_aligned;
+	struct ether_addr d_addr;
+
+	struct ether_hdr *eth_hdr;
+	struct arp_hdr *arp_hdr;
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t ether_type, offset;
+
+	uint16_t rx_cnt;
+	uint32_t bond_ip;
+	int i = 0;
+	uint8_t is_free;
+
+	bond_ip = BOND_IP_1 | (BOND_IP_2 << 8) |
+				(BOND_IP_3 << 16) | (BOND_IP_4 << 24);
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+
+	while (global_flag_stru_p->LcoreMainIsRunning) {
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		rx_cnt = rte_eth_rx_burst(BOND_PORT, 0, pkts, MAX_PKT_BURST);
+		is_free = 0;
+
+		/* If didn't receive any packets, wait and go to next iteration */
+		if (rx_cnt == 0) {
+			rte_delay_us(50);
+			continue;
+		}
+
+		/* Search incoming data for ARP packets and prepare response */
+		for (i = 0; i < rx_cnt; i++) {
+			if (rte_spinlock_trylock(&global_flag_stru_p->lock) == 1) {
+				global_flag_stru_p->port_packets[0]++;
+				rte_spinlock_unlock(&global_flag_stru_p->lock);
+			}
+			eth_hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+			ether_type = eth_hdr->ether_type;
+			if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+				printf("VLAN taged frame, offset:");
+			}
+			offset = get_vlan_offset(eth_hdr, &ether_type);
+			if (offset > 0)
+				printf("%d\n", offset);
+			if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+				if (rte_spinlock_trylock(&global_flag_stru_p->lock) == 1)     {
+					global_flag_stru_p->port_packets[1]++;
+					rte_spinlock_unlock(&global_flag_stru_p->lock);
+				}
+				arp_hdr = (struct arp_hdr *)((char *)(eth_hdr + 1) + offset);
+				if (arp_hdr->arp_data.arp_tip == bond_ip) {
+					if (arp_hdr->arp_op == rte_cpu_to_be_16(ARP_OP_REQUEST)) {
+						arp_hdr->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
+						/* Switch src and dst data and set bonding MAC */
+						ether_addr_copy(&eth_hdr->s_addr, &eth_hdr->d_addr);
+						rte_eth_macaddr_get(BOND_PORT, &eth_hdr->s_addr);
+						ether_addr_copy(&arp_hdr->arp_data.arp_sha, &arp_hdr->arp_data.arp_tha);
+						arp_hdr->arp_data.arp_tip = arp_hdr->arp_data.arp_sip;
+						rte_eth_macaddr_get(BOND_PORT, &d_addr);
+						ether_addr_copy(&d_addr, &arp_hdr->arp_data.arp_sha);
+						arp_hdr->arp_data.arp_sip = bond_ip;
+						rte_eth_tx_burst(BOND_PORT, 0, &pkts[i], 1);
+						is_free = 1;
+					} else {
+						rte_eth_tx_burst(BOND_PORT, 0, NULL, 0);
+					}
+				}
+			} else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+				if (rte_spinlock_trylock(&global_flag_stru_p->lock) == 1)     {
+					global_flag_stru_p->port_packets[2]++;
+					rte_spinlock_unlock(&global_flag_stru_p->lock);
+				 }
+				ipv4_hdr = (struct ipv4_hdr *)((char *)(eth_hdr + 1) + offset);
+				if (ipv4_hdr->dst_addr == bond_ip) {
+					ether_addr_copy(&eth_hdr->s_addr, &eth_hdr->d_addr);
+					rte_eth_macaddr_get(BOND_PORT, &eth_hdr->s_addr);
+					ipv4_hdr->dst_addr = ipv4_hdr->src_addr;
+					ipv4_hdr->src_addr = bond_ip;
+					rte_eth_tx_burst(BOND_PORT, 0, &pkts[i], 1);
+				}
+
+			}
+
+			/* Free processed packets */
+			if (is_free == 0)
+				rte_pktmbuf_free(pkts[i]);
+		}
+		rte_spinlock_trylock(&global_flag_stru_p->lock);
+	}
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+	printf("BYE lcore_main\n");
+	return 0;
+}
+
+struct cmd_obj_send_result {
+	cmdline_fixed_string_t action;
+	cmdline_ipaddr_t ip;
+};
+
+static void cmd_obj_send_parsed(void *parsed_result,
+		__attribute__((unused)) struct cmdline *cl,
+			       __attribute__((unused)) void *data)
+{
+
+	struct cmd_obj_send_result *res = parsed_result;
+	char ip_str[INET6_ADDRSTRLEN];
+
+	struct rte_mbuf *created_pkt;
+	struct ether_hdr *eth_hdr;
+	struct arp_hdr *arp_hdr;
+
+	uint32_t bond_ip;
+	size_t pkt_size;
+
+	if (res->ip.family == AF_INET)
+		snprintf(ip_str, sizeof(ip_str), NIPQUAD_FMT,
+			NIPQUAD(res->ip.addr.ipv4));
+	else
+		cmdline_printf(cl, "Wrong IP format. Only IPv4 is supported\n");
+
+	bond_ip = BOND_IP_1 | (BOND_IP_2 << 8) |
+				(BOND_IP_3 << 16) | (BOND_IP_4 << 24);
+
+	created_pkt = rte_pktmbuf_alloc(mbuf_pool);
+	while (created_pkt == NULL);
+	pkt_size = sizeof(struct ether_hdr) + sizeof(struct arp_hdr);
+	created_pkt->data_len = pkt_size;
+	created_pkt->pkt_len = pkt_size;
+
+	eth_hdr = rte_pktmbuf_mtod(created_pkt, struct ether_hdr *);
+	rte_eth_macaddr_get(BOND_PORT, &eth_hdr->s_addr);
+	memset(&eth_hdr->d_addr, 0xFF, ETHER_ADDR_LEN);
+	eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+
+	arp_hdr = (struct arp_hdr *)((char *)eth_hdr + sizeof(struct ether_hdr));
+	arp_hdr->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
+	arp_hdr->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	arp_hdr->arp_hln = ETHER_ADDR_LEN;
+	arp_hdr->arp_pln = sizeof(uint32_t);
+	arp_hdr->arp_op = rte_cpu_to_be_16(ARP_OP_REQUEST);
+
+	rte_eth_macaddr_get(BOND_PORT, &arp_hdr->arp_data.arp_sha);
+	arp_hdr->arp_data.arp_sip = bond_ip;
+	memset(&arp_hdr->arp_data.arp_tha, 0, ETHER_ADDR_LEN);
+	arp_hdr->arp_data.arp_tip =
+			  ((unsigned char *)&res->ip.addr.ipv4)[0]        |
+			 (((unsigned char *)&res->ip.addr.ipv4)[1] << 8)  |
+			 (((unsigned char *)&res->ip.addr.ipv4)[2] << 16) |
+			 (((unsigned char *)&res->ip.addr.ipv4)[3] << 24);
+	rte_eth_tx_burst(BOND_PORT, 0, &created_pkt, 1);
+
+	rte_delay_ms(100);
+	cmdline_printf(cl, "\n");
+}
+
+cmdline_parse_token_string_t cmd_obj_action_send =
+	TOKEN_STRING_INITIALIZER(struct cmd_obj_send_result, action, "send");
+cmdline_parse_token_ipaddr_t cmd_obj_ip =
+	TOKEN_IPV4_INITIALIZER(struct cmd_obj_send_result, ip);
+
+cmdline_parse_inst_t cmd_obj_send = {
+	.f = cmd_obj_send_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "send client_ip",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_obj_action_send,
+		(void *)&cmd_obj_ip,
+		NULL,
+	},
+};
+
+struct cmd_start_result {
+	cmdline_fixed_string_t start;
+};
+
+static void cmd_start_parsed(__attribute__((unused)) void *parsed_result,
+			       struct cmdline *cl,
+			       __attribute__((unused)) void *data)
+{
+	int slave_core_id = rte_lcore_id();
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	if (global_flag_stru_p->LcoreMainIsRunning == 0)	{
+		if (lcore_config[global_flag_stru_p->LcoreMainCore].state != WAIT)	{
+			rte_spinlock_unlock(&global_flag_stru_p->lock);
+			return;
+		}
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+	} else {
+		cmdline_printf(cl, "lcore_main already running on core:%d\n",
+				global_flag_stru_p->LcoreMainCore);
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		return;
+	}
+
+	/* start lcore main on core != master_core - ARP response thread */
+	slave_core_id = rte_get_next_lcore(rte_lcore_id(), 1, 0);
+	if ((slave_core_id >= RTE_MAX_LCORE) || (slave_core_id == 0))
+		return;
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	global_flag_stru_p->LcoreMainIsRunning = 1;
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+	cmdline_printf(cl, "Starting lcore_main on core %d:%d "
+			"Our IP:%d.%d.%d.%d\n",
+			slave_core_id,
+			rte_eal_remote_launch(lcore_main, NULL, slave_core_id),
+			BOND_IP_1,
+			BOND_IP_2,
+			BOND_IP_3,
+			BOND_IP_4
+		);
+}
+
+cmdline_parse_token_string_t cmd_start_start =
+	TOKEN_STRING_INITIALIZER(struct cmd_start_result, start, "start");
+
+cmdline_parse_inst_t cmd_start = {
+	.f = cmd_start_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "starts listening if not started at startup",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_start_start,
+		NULL,
+	},
+};
+
+struct cmd_help_result {
+	cmdline_fixed_string_t help;
+};
+
+static void cmd_help_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	cmdline_printf(cl,
+			"ALB - link bonding mode 6 example\n"
+			"send IP	- sends one ARPrequest thru bonding for IP.\n"
+			"start		- starts listening ARPs.\n"
+			"stop		- stops lcore_main.\n"
+			"show		- shows some bond info: ex. active slaves etc.\n"
+			"help		- prints help.\n"
+			"quit		- terminate all threads and quit.\n"
+		       );
+}
+
+cmdline_parse_token_string_t cmd_help_help =
+	TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
+
+cmdline_parse_inst_t cmd_help = {
+	.f = cmd_help_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "show help",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_help_help,
+		NULL,
+	},
+};
+
+struct cmd_stop_result {
+	cmdline_fixed_string_t stop;
+};
+
+static void cmd_stop_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	if (global_flag_stru_p->LcoreMainIsRunning == 0)	{
+		cmdline_printf(cl,
+					"lcore_main not running on core:%d\n",
+					global_flag_stru_p->LcoreMainCore);
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		return;
+	}
+	global_flag_stru_p->LcoreMainIsRunning = 0;
+	rte_eal_wait_lcore(global_flag_stru_p->LcoreMainCore);
+	cmdline_printf(cl,
+			"lcore_main stopped on core:%d\n",
+			global_flag_stru_p->LcoreMainCore);
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+}
+
+cmdline_parse_token_string_t cmd_stop_stop =
+	TOKEN_STRING_INITIALIZER(struct cmd_stop_result, stop, "stop");
+
+cmdline_parse_inst_t cmd_stop = {
+	.f = cmd_stop_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "this command do not handle any arguments",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_stop_stop,
+		NULL,
+	},
+};
+
+struct cmd_quit_result {
+	cmdline_fixed_string_t quit;
+};
+
+static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	if (global_flag_stru_p->LcoreMainIsRunning == 0)	{
+		cmdline_printf(cl,
+					"lcore_main not running on core:%d\n",
+					global_flag_stru_p->LcoreMainCore);
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		cmdline_quit(cl);
+		return;
+	}
+	global_flag_stru_p->LcoreMainIsRunning = 0;
+	rte_eal_wait_lcore(global_flag_stru_p->LcoreMainCore);
+	cmdline_printf(cl,
+			"lcore_main stopped on core:%d\n",
+			global_flag_stru_p->LcoreMainCore);
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+	cmdline_quit(cl);
+	return;
+}
+
+cmdline_parse_token_string_t cmd_quit_quit =
+	TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
+
+cmdline_parse_inst_t cmd_quit = {
+	.f = cmd_quit_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "this command do not handle any arguments",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_quit_quit,
+		NULL,
+	},
+};
+
+extern void print_client_stats(void);
+struct cmd_show_result {
+	cmdline_fixed_string_t show;
+};
+
+static void cmd_show_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	uint8_t slaves[16] = {0};
+	uint8_t len = 16;
+	struct ether_addr addr;
+	uint8_t i = 0;
+
+	while (i < slaves_count)	{
+		rte_eth_macaddr_get(i, &addr);
+		PRINT_MAC(addr);
+		printf("\n");
+		i++;
+	}
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	cmdline_printf(cl,
+			"Active_slaves:%d "
+			"packets received:Tot:%d Arp:%d IPv4:%d\n",
+			rte_eth_bond_active_slaves_get(BOND_PORT, slaves, len),
+			global_flag_stru_p->port_packets[0], \
+			global_flag_stru_p->port_packets[1], \
+			global_flag_stru_p->port_packets[2]);
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1) || defined(RTE_LIBRTE_BOND_DEBUG_ALB)
+	print_client_stats();
+#endif
+}
+
+cmdline_parse_token_string_t cmd_show_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_result, show, "show");
+
+cmdline_parse_inst_t cmd_show = {
+	.f = cmd_show_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "this command do not handle any arguments",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_show_show,
+		NULL,
+	},
+};
+
+/****** CONTEXT (list of instruction) */
+
+cmdline_parse_ctx_t main_ctx[] = {
+	(cmdline_parse_inst_t *)&cmd_start,
+	(cmdline_parse_inst_t *)&cmd_obj_send,
+	(cmdline_parse_inst_t *)&cmd_stop,
+	(cmdline_parse_inst_t *)&cmd_show,
+	(cmdline_parse_inst_t *)&cmd_quit,
+	(cmdline_parse_inst_t *)&cmd_help,
+	NULL,
+};
+
+/* prompt function, called from main on MASTER lcore */
+static void *prompt(__attribute__((unused)) void *arg1)
+{
+	struct cmdline *cl;
+
+	cl = cmdline_stdin_new(main_ctx, "bond6>");
+	if (cl != NULL) {
+		cmdline_interact(cl);
+		cmdline_stdin_exit(cl);
+	}
+}
+
+/* Main function, does initialisation and calls the per-lcore functions */
+int
+MAIN(int argc, char *argv[])
+{
+	int ret;
+	uint8_t nb_ports, i;
+
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	rte_eal_devargs_dump(stdout);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
+	argc -= ret;
+	argv += ret;
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "Give at least one port\n");
+	else if (nb_ports > MAX_PORTS)
+		rte_exit(EXIT_FAILURE, "You can have max 4 ports\n");
+
+	mbuf_pool = rte_mempool_create("MBUF_POOL", NB_MBUF,
+				       MBUF_SIZE, 32,
+				       sizeof(struct rte_pktmbuf_pool_private),
+				       rte_pktmbuf_pool_init, NULL,
+				       rte_pktmbuf_init, NULL,
+				       rte_socket_id(), 0);
+	if (mbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
+
+	/* initialize all ports */
+	slaves_count = nb_ports;
+	for (i = 0; i < nb_ports; i++) {
+		slave_port_init(i, mbuf_pool);
+		slaves[i] = i;
+	}
+
+	bond_port_init(mbuf_pool);
+
+	rte_spinlock_init(&global_flag_stru_p->lock);
+	int slave_core_id = rte_lcore_id();
+
+	/* check state of lcores */
+	RTE_LCORE_FOREACH_SLAVE(slave_core_id) {
+	if (lcore_config[slave_core_id].state != WAIT)
+		return -EBUSY;
+	}
+	/* start lcore main on core != master_core - ARP response thread */
+	slave_core_id = rte_get_next_lcore(rte_lcore_id(), 1, 0);
+	if ((slave_core_id >= RTE_MAX_LCORE) || (slave_core_id == 0))
+		return -EPERM;
+
+	global_flag_stru_p->LcoreMainIsRunning = 1;
+	global_flag_stru_p->LcoreMainCore = slave_core_id;
+	printf("Starting lcore_main on core %d:%d Our IP:%d.%d.%d.%d\n",
+			slave_core_id,
+			rte_eal_remote_launch((lcore_function_t *)lcore_main,
+					NULL,
+					slave_core_id),
+			BOND_IP_1,
+			BOND_IP_2,
+			BOND_IP_3,
+			BOND_IP_4
+		);
+
+	/* Start prompt for user interact */
+	prompt(NULL);
+
+	rte_delay_ms(100);
+	return 0;
+}
diff --git a/examples/bond/main.h b/examples/bond/main.h
new file mode 100644
index 0000000..2682d15
--- /dev/null
+++ b/examples/bond/main.h
@@ -0,0 +1,46 @@
+/*-
+ *   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 _MAIN_H_
+#define _MAIN_H_
+
+
+#ifdef RTE_EXEC_ENV_BAREMETAL
+#define MAIN _main
+#else
+#define MAIN main
+#endif
+
+int MAIN(int argc, char *argv[]);
+
+#endif /* ifndef _MAIN_H_ */
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v2 5/6] bond: modify TLB unit tests
  2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                   ` (3 preceding siblings ...)
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
@ 2015-02-13 15:16 ` Michal Jastrzebski
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 6/6] bond: add unit tests for link bonding mode 6 Michal Jastrzebski
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-13 15:16 UTC (permalink / raw)
  To: dev

This patch modify mode older name from 
BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING to BONDING_MODE_TLB
that was used in unittests.
It also changes 

Signed-off-by: Daniel Mrzyglod  <danielx.t.mrzyglod@intel.com>
---
 app/test/test_link_bonding.c            |   27 ++++++++++++++-------------
 lib/librte_pmd_bond/rte_eth_bond.h      |    2 +-
 lib/librte_pmd_bond/rte_eth_bond_api.c  |    8 ++++----
 lib/librte_pmd_bond/rte_eth_bond_args.c |    2 +-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c  |   12 ++++++------
 5 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index 579ebbf..dd6e357 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -4053,7 +4053,7 @@ test_tlb_tx_burst(void)
 	uint64_t floor_obytes = 0, ceiling_obytes = 0;
 
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves
-			(BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 1, 3, 1),
+			(BONDING_MODE_TLB, 1, 3, 1),
 			"Failed to initialise bonded device");
 
 	burst_size = 20 * test_params->bonded_slave_count;
@@ -4153,7 +4153,7 @@ test_tlb_rx_burst(void)
 
 	/* Initialize bonded device with 4 slaves in transmit load balancing mode */
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING,
+			BONDING_MODE_TLB,
 			TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1, 1),
 			"Failed to initialize bonded device");
 
@@ -4231,7 +4231,7 @@ test_tlb_verify_promiscuous_enable_disable(void)
 
 	/* Initialize bonded device with 4 slaves in transmit load balancing mode */
 	TEST_ASSERT_SUCCESS( initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 4, 1),
+			BONDING_MODE_TLB, 0, 4, 1),
 			"Failed to initialize bonded device");
 
 	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
@@ -4289,7 +4289,7 @@ test_tlb_verify_mac_assignment(void)
 
 	/* Initialize bonded device with 2 slaves in active backup mode */
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 2, 1),
+			BONDING_MODE_TLB, 0, 2, 1),
 			"Failed to initialize bonded device");
 
 	/* Verify that bonded MACs is that of first slave and that the other slave
@@ -4409,7 +4409,7 @@ test_tlb_verify_slave_link_status_change_failover(void)
 
 	/* Initialize bonded device with 4 slaves in round robin mode */
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0,
+			BONDING_MODE_TLB, 0,
 			TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1),
 			"Failed to initialize bonded device with slaves");
 
@@ -4472,20 +4472,21 @@ test_tlb_verify_slave_link_status_change_failover(void)
 		rte_delay_us(11000);
 	}
 
-	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
-	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
-			"(%d) port_stats.opackets not as expected\n",
-			test_params->slave_port_ids[2]);
-
 	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
 	TEST_ASSERT_EQUAL(port_stats.opackets, (int8_t)0,
-			"(%d) port_stats.opackets not as expected\n",
-			test_params->slave_port_ids[0]);
+				"(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
+					"(%d) port_stats.opackets not as expected\n",
+					test_params->slave_port_ids[1]);
+
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
 			"(%d) port_stats.opackets not as expected\n",
-			test_params->slave_port_ids[1]);
+			test_params->slave_port_ids[2]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
diff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h
index 13581cb..4117a70 100644
--- a/lib/librte_pmd_bond/rte_eth_bond.h
+++ b/lib/librte_pmd_bond/rte_eth_bond.h
@@ -96,7 +96,7 @@ extern "C" {
  * to rx_burst should be at least 2 times the slave count size.
  *
  */
-#define BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING	(5)
+#define BONDING_MODE_TLB	(5)
 /**< Adaptive TLB (Mode 5)
  * This mode provides an adaptive transmit load balancing. It dynamically
  * changes the transmitting slave, according to the computed load. Statistics
diff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c
index cbfd185..a5f2c26 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_api.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c
@@ -116,7 +116,7 @@ activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_activate_slave(eth_dev, port_id);
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+	if (internals->mode == BONDING_MODE_TLB
 			|| internals->mode == BONDING_MODE_ALB) {
 
 		internals->tlb_slaves_order[active_count] = port_id;
@@ -128,7 +128,7 @@ activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	internals->active_slaves[internals->active_slave_count] = port_id;
 	internals->active_slave_count++;
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)
+	if (internals->mode == BONDING_MODE_TLB)
 		bond_tlb_activate_slave(internals);
 	if (internals->mode == BONDING_MODE_ALB)
 		bond_mode_alb_client_list_upd(eth_dev);
@@ -144,7 +144,7 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (internals->mode == BONDING_MODE_8023AD) {
 		bond_mode_8023ad_stop(eth_dev);
 		bond_mode_8023ad_deactivate_slave(eth_dev, port_id);
-	} else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+	} else if (internals->mode == BONDING_MODE_TLB
 			|| internals->mode == BONDING_MODE_ALB)
 		bond_tlb_disable(internals);
 
@@ -167,7 +167,7 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (eth_dev->data->dev_started) {
 	   if (internals->mode == BONDING_MODE_8023AD) {
 			   bond_mode_8023ad_start(eth_dev);
-	   } else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {
+	   } else if (internals->mode == BONDING_MODE_TLB) {
 			   bond_tlb_enable(internals);
 	   } else if (internals->mode == BONDING_MODE_ALB) {
 			   bond_tlb_enable(internals);
diff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c
index a3f7f55..0801cb5 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_args.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c
@@ -174,7 +174,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,
 	case BONDING_MODE_BROADCAST:
 #endif
 	case BONDING_MODE_8023AD:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 		return 0;
 	default:
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index f469b5c..a473e5d 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -1225,7 +1225,7 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
 		bond_mode_8023ad_mac_address_update(bonded_eth_dev);
 		break;
 	case BONDING_MODE_ACTIVE_BACKUP:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 	default:
 		for (i = 0; i < internals->slave_count; i++) {
@@ -1288,7 +1288,7 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
 				"Using mode 4, it is necessary to do TX burst and RX burst "
 				"at least every 100ms.");
 		break;
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb;
 		eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup;
 		break;
@@ -1514,7 +1514,7 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_start(eth_dev);
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+	if (internals->mode == BONDING_MODE_TLB ||
 			internals->mode == BONDING_MODE_ALB)
 		bond_tlb_enable(internals);
 
@@ -1547,7 +1547,7 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)
 		}
 	}
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+	if (internals->mode == BONDING_MODE_TLB ||
 			internals->mode == BONDING_MODE_ALB) {
 		bond_tlb_disable(internals);
 		for (i = 0; i < internals->active_slave_count; i++)
@@ -1807,7 +1807,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
 		break;
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_enable(internals->current_primary_port);
@@ -1837,7 +1837,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
 		break;
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_disable(internals->current_primary_port);
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v2 6/6] bond: add unit tests for link bonding mode 6.
  2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                   ` (4 preceding siblings ...)
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 5/6] bond: modify TLB unit tests Michal Jastrzebski
@ 2015-02-13 15:16 ` Michal Jastrzebski
  2015-02-13 16:12 ` [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Declan Doherty
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-13 15:16 UTC (permalink / raw)
  To: dev

Added 4 unit tests checking link bonding mode 6 behavior.

Also modified virtual_pmd so it is possible to provide packets,
that should be received with rx_burst and to inspect packets
transmitted by tx_burst.

In packet_burst_generator.c function creating eth_header is
modified, so it accepts ether_type as a parameter and function
creating arp_header is added. Updated other unit tests to get
rid of compilation errors.

Signed-off-by: Maciej Gajdzica  <maciejx.t.gajdzica@intel.com>
---
 app/test/packet_burst_generator.c |   41 ++--
 app/test/packet_burst_generator.h |   11 +-
 app/test/test_link_bonding.c      |  411 +++++++++++++++++++++++++++++++++++--
 app/test/test_pmd_perf.c          |    3 +-
 app/test/virtual_pmd.c            |  103 ++++++----
 app/test/virtual_pmd.h            |    5 +-
 6 files changed, 499 insertions(+), 75 deletions(-)

diff --git a/app/test/packet_burst_generator.c b/app/test/packet_burst_generator.c
index e9d059c..b46eed7 100644
--- a/app/test/packet_burst_generator.c
+++ b/app/test/packet_burst_generator.c
@@ -80,11 +80,10 @@ copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
 	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 ipv4, uint8_t vlan_enabled,
-		uint16_t van_id)
+		struct ether_addr *dst_mac, uint16_t ether_type,
+		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);
@@ -95,19 +94,27 @@ initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
 
 		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
 
-		if (ipv4)
-			vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv4);
-		else
-			vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv6);
-
+		vhdr->eth_proto =  rte_cpu_to_be_16(ether_type);
 		vhdr->vlan_tci = van_id;
 	} else {
-		if (ipv4)
-			eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
-		else
-			eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		eth_hdr->ether_type = rte_cpu_to_be_16(ether_type);
 	}
+}
 
+void
+initialize_arp_header(struct arp_hdr *arp_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint32_t src_ip, uint32_t dst_ip,
+		uint32_t opcode)
+{
+	arp_hdr->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
+	arp_hdr->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	arp_hdr->arp_hln = ETHER_ADDR_LEN;
+	arp_hdr->arp_pln = sizeof(uint32_t);
+	arp_hdr->arp_op = rte_cpu_to_be_16(opcode);
+	ether_addr_copy(src_mac, &arp_hdr->arp_data.arp_sha);
+	arp_hdr->arp_data.arp_sip = src_ip;
+	ether_addr_copy(dst_mac, &arp_hdr->arp_data.arp_tha);
+	arp_hdr->arp_data.arp_tip = dst_ip;
 }
 
 uint16_t
@@ -265,9 +272,19 @@ nomore_mbuf:
 		if (ipv4) {
 			pkt->vlan_tci  = ETHER_TYPE_IPv4;
 			pkt->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->vlan_tci  = ETHER_TYPE_IPv6;
 			pkt->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;
diff --git a/app/test/packet_burst_generator.h b/app/test/packet_burst_generator.h
index 666cc8e..edc1044 100644
--- a/app/test/packet_burst_generator.h
+++ b/app/test/packet_burst_generator.h
@@ -40,6 +40,7 @@ extern "C" {
 
 #include <rte_mbuf.h>
 #include <rte_ether.h>
+#include <rte_arp.h>
 #include <rte_ip.h>
 #include <rte_udp.h>
 
@@ -50,11 +51,15 @@ extern "C" {
 #define PACKET_BURST_GEN_PKT_LEN 60
 #define PACKET_BURST_GEN_PKT_LEN_128 128
 
-
 void
 initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
-		struct ether_addr *dst_mac, uint8_t ipv4, uint8_t vlan_enabled,
-		uint16_t van_id);
+		struct ether_addr *dst_mac, uint16_t ether_type,
+		uint8_t vlan_enabled, uint16_t van_id);
+
+void
+initialize_arp_header(struct arp_hdr *arp_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint32_t src_ip, uint32_t dst_ip,
+		uint32_t opcode);
 
 uint16_t
 initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index dd6e357..30d66e9 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -1313,17 +1313,22 @@ 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;
+	uint16_t pktlen, generated_burst_size, ether_type;
 	void *ip_hdr;
 
+	if (ipv4)
+		ether_type = ETHER_TYPE_IPv4;
+	else
+		ether_type = ETHER_TYPE_IPv6;
+
 	if (toggle_dst_mac)
 		initialize_eth_header(test_params->pkt_eth_hdr,
 				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
-				ipv4, vlan, vlan_id);
+				ether_type, vlan, vlan_id);
 	else
 		initialize_eth_header(test_params->pkt_eth_hdr,
 				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
-				ipv4, vlan, vlan_id);
+				ether_type, vlan, vlan_id);
 
 
 	if (toggle_udp_port)
@@ -2094,7 +2099,8 @@ test_activebackup_tx_burst(void)
 			"Failed to initialize bonded device with slaves");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+			ETHER_TYPE_IPv4,  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,
@@ -2637,7 +2643,8 @@ test_balance_l2_tx_burst(void)
 			"Failed to set balance xmit policy.");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+			ETHER_TYPE_IPv4, 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,
@@ -2651,7 +2658,8 @@ test_balance_l2_tx_burst(void)
 			"failed to generate packet burst");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
+			ETHER_TYPE_IPv4, 0, 0);
 
 	/* Generate a burst 2 of packets to transmit */
 	TEST_ASSERT_EQUAL(generate_packet_burst(test_params->mbuf_pool, &pkts_burst[1][0],
@@ -3488,7 +3496,8 @@ test_broadcast_tx_burst(void)
 			"Failed to intialise bonded device");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+			ETHER_TYPE_IPv4, 0, 0);
 
 	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
 			dst_port_0, 16);
@@ -4041,6 +4050,24 @@ testsuite_teardown(void)
 	return remove_slaves_and_stop_bonded_device();
 }
 
+static void
+free_virtualpmd_tx_queue(void)
+{
+	int i, slave_port, to_free_cnt;
+	struct rte_mbuf *pkts_to_free[MAX_PKT_BURST];
+
+	/* Free tx queue of virtual pmd */
+	for (slave_port = 0; slave_port < test_params->bonded_slave_count;
+			slave_port++) {
+		to_free_cnt = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_port],
+				pkts_to_free, MAX_PKT_BURST);
+		for (i = 0; i < to_free_cnt; i++) {
+			rte_pktmbuf_free(pkts_to_free[i]);
+		}
+	}
+}
+
 static int
 test_tlb_tx_burst(void)
 {
@@ -4068,11 +4095,11 @@ test_tlb_tx_burst(void)
 		if (i % 2 == 0) {
 			initialize_eth_header(test_params->pkt_eth_hdr,
 					(struct ether_addr *)src_mac,
-					(struct ether_addr *)dst_mac_0, 1, 0, 0);
+					(struct ether_addr *)dst_mac_0, ETHER_TYPE_IPv4, 0, 0);
 		} else {
 			initialize_eth_header(test_params->pkt_eth_hdr,
 					(struct ether_addr *)test_params->default_slave_mac,
-					(struct ether_addr *)dst_mac_0, 1, 0, 0);
+					(struct ether_addr *)dst_mac_0, ETHER_TYPE_IPv4, 0, 0);
 		}
 		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
 				dst_port_0, 16);
@@ -4086,6 +4113,8 @@ test_tlb_tx_burst(void)
 				burst_size);
 		nb_tx2 += nb_tx;
 
+		free_virtualpmd_tx_queue();
+
 		TEST_ASSERT_EQUAL(nb_tx, burst_size,
 				"number of packet not equal burst size");
 
@@ -4474,14 +4503,13 @@ test_tlb_verify_slave_link_status_change_failover(void)
 
 	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
 	TEST_ASSERT_EQUAL(port_stats.opackets, (int8_t)0,
-				"(%d) port_stats.opackets not as expected\n",
-				test_params->slave_port_ids[0]);
+			"(%d) port_stats.opackets not as expected\n",
+			test_params->slave_port_ids[0]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
-					"(%d) port_stats.opackets not as expected\n",
-					test_params->slave_port_ids[1]);
-
+			"(%d) port_stats.opackets not as expected\n",
+			test_params->slave_port_ids[1]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
@@ -4534,6 +4562,357 @@ test_tlb_verify_slave_link_status_change_failover(void)
 	return remove_slaves_and_stop_bonded_device();
 }
 
+#define TEST_ALB_SLAVE_COUNT	2
+
+static uint8_t mac_client1[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 1};
+static uint8_t mac_client2[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 2};
+static uint8_t mac_client3[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 3};
+static uint8_t mac_client4[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 4};
+
+static uint32_t ip_host = IPV4_ADDR(192, 168, 0, 0);
+static uint32_t ip_client1 = IPV4_ADDR(192, 168, 0, 1);
+static uint32_t ip_client2 = IPV4_ADDR(192, 168, 0, 2);
+static uint32_t ip_client3 = IPV4_ADDR(192, 168, 0, 3);
+static uint32_t ip_client4 = IPV4_ADDR(192, 168, 0, 4);
+
+static int
+test_alb_change_mac_in_reply_sent(void)
+{
+	struct rte_mbuf *pkt;
+	struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+	struct ether_hdr *eth_pkt;
+	struct arp_hdr *arp_pkt;
+
+	int slave_idx, nb_pkts, pkt_idx;
+	int retval = 0;
+
+	struct ether_addr bond_mac, client_mac;
+	struct ether_addr *slave_mac1, *slave_mac2;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	/* Flush tx queue */
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count;
+			slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+	}
+
+	ether_addr_copy(
+			rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+			&bond_mac);
+
+	/*
+	 * Generating four packets with different mac and ip addresses and sending
+	 * them through the bonding port.
+	 */
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, 0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client1, ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, 0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client2, ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, 0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client3, ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, 0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client4, ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	slave_mac1 = rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs;
+	slave_mac2 = rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs;
+
+	/*
+	 * Checking if packets are properly distributed on bonding ports. Packets
+	 * 0 and 2 should be sent on port 0 and packets 1 and 3 on port 1.
+	 */
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent, MAX_PKT_BURST);
+
+		for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+			eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+			arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+
+			if (slave_idx%2 == 0) {
+				if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			} else {
+				if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			}
+		}
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
+
+static int
+test_alb_reply_from_client(void)
+{
+	struct ether_hdr *eth_pkt;
+	struct arp_hdr *arp_pkt;
+
+	struct rte_mbuf *pkt;
+	struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+	int slave_idx, nb_pkts, pkt_idx, nb_pkts_sum = 0;
+	int retval = 0;
+
+	struct ether_addr bond_mac, client_mac;
+	struct ether_addr *slave_mac1, *slave_mac2;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	/* Flush tx queue */
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent, MAX_PKT_BURST);
+	}
+
+	ether_addr_copy(
+			rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+			&bond_mac);
+
+	/*
+	 * Generating four packets with different mac and ip addresses and placing
+	 * them in the rx queue to be received by the bonding driver on rx_burst.
+	 */
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, 0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host, ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, 0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client2, ip_host, ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, 0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client3, ip_host, ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, 0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client4, ip_host, ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, 1);
+
+	/*
+	 * Issue rx_burst and tx_burst to force bonding driver to send update ARP
+	 * packets to every client in alb table.
+	 */
+	rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+
+	slave_mac1 = rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs;
+	slave_mac2 = rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs;
+
+	/*
+	 * Checking if update ARP packets were properly send on slave ports.
+	 */
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent, MAX_PKT_BURST);
+		nb_pkts_sum += nb_pkts;
+
+		for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+			eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+			arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+
+			if (slave_idx%2 == 0) {
+				if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			} else {
+				if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			}
+		}
+	}
+
+	/* Check if proper number of packets was send */
+	if (nb_pkts_sum < 4) {
+		retval = -1;
+		goto test_end;
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
+
+static int
+test_alb_receive_vlan_reply(void)
+{
+	struct ether_hdr *eth_pkt;
+	struct vlan_hdr *vlan_pkt;
+	struct arp_hdr *arp_pkt;
+
+	struct rte_mbuf *pkt;
+	struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+	int slave_idx, nb_pkts, pkt_idx;
+	int retval = 0;
+
+	struct ether_addr bond_mac, client_mac;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	/* Flush tx queue */
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent, MAX_PKT_BURST);
+	}
+
+	ether_addr_copy(
+			rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+			&bond_mac);
+
+	/*
+	 * Generating packet with double VLAN header and placing it in the rx queue.
+	 */
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_VLAN, 0, 0);
+	vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1));
+	vlan_pkt->vlan_tci = rte_cpu_to_be_16(1);
+	vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	vlan_pkt = vlan_pkt+1;
+	vlan_pkt->vlan_tci = rte_cpu_to_be_16(2);
+	vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+	arp_pkt = (struct arp_hdr *)((char *)(vlan_pkt + 1));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host, ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, 1);
+
+	rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+
+	/*
+	 * Checking if VLAN headers in generated ARP Update packet are correct.
+	 */
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent, MAX_PKT_BURST);
+
+		for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+			eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+			vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1));
+			if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(1)) {
+				retval = -1;
+				goto test_end;
+			}
+			if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+				retval = -1;
+				goto test_end;
+			}
+			vlan_pkt = vlan_pkt+1;
+			if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(2)) {
+				retval = -1;
+				goto test_end;
+			}
+			if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+				retval = -1;
+				goto test_end;
+			}
+		}
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
+
+static int
+test_alb_ipv4_tx(void)
+{
+	int burst_size, retval, pkts_send;
+	struct rte_mbuf *pkt_burst[MAX_PKT_BURST];
+
+	retval = 0;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	burst_size = 32;
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0) != burst_size) {
+		retval = -1;
+		goto test_end;
+	}
+
+	/*
+	 * Checking if ipv4 traffic is transmitted via TLB policy.
+	 */
+	pkts_send = rte_eth_tx_burst(
+			test_params->bonded_port_id, 0, pkt_burst, burst_size);
+	if (pkts_send != burst_size) {
+		retval = -1;
+		goto test_end;
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
 
 static struct unit_test_suite link_bonding_test_suite  = {
 	.suite_name = "Link Bonding Unit Test Suite",
@@ -4593,6 +4972,10 @@ static struct unit_test_suite link_bonding_test_suite  = {
 		TEST_CASE(test_tlb_verify_mac_assignment),
 		TEST_CASE(test_tlb_verify_promiscuous_enable_disable),
 		TEST_CASE(test_tlb_verify_slave_link_status_change_failover),
+		TEST_CASE(test_alb_change_mac_in_reply_sent),
+		TEST_CASE(test_alb_reply_from_client),
+		TEST_CASE(test_alb_receive_vlan_reply),
+		TEST_CASE(test_alb_ipv4_tx),
 #ifdef RTE_MBUF_REFCNT
 		TEST_CASE(test_broadcast_tx_burst),
 		TEST_CASE(test_broadcast_tx_burst_slave_tx_fail),
diff --git a/app/test/test_pmd_perf.c b/app/test/test_pmd_perf.c
index bad9503..d6a4a45 100644
--- a/app/test/test_pmd_perf.c
+++ b/app/test/test_pmd_perf.c
@@ -235,8 +235,7 @@ init_traffic(struct rte_mempool *mp,
 
 	initialize_eth_header(&pkt_eth_hdr,
 		(struct ether_addr *)src_mac,
-		(struct ether_addr *)dst_mac, 1, 0, 0);
-	pkt_eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		(struct ether_addr *)dst_mac, ETHER_TYPE_IPv4, 0, 0);
 
 	pktlen = initialize_ipv4_header(&pkt_ipv4_hdr,
 					IPV4_ADDR(10, 0, 0, 1),
diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
index 9fac95d..dcc7d05 100644
--- a/app/test/virtual_pmd.c
+++ b/app/test/virtual_pmd.c
@@ -36,6 +36,7 @@
 #include <rte_malloc.h>
 #include <rte_memcpy.h>
 #include <rte_memory.h>
+#include <rte_ring.h>
 
 #include "virtual_pmd.h"
 
@@ -46,8 +47,8 @@ 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 rte_ring *rx_queue;
+	struct rte_ring *tx_queue;
 
 	int tx_burst_fail_count;
 };
@@ -74,8 +75,16 @@ virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev __rte_unused)
 }
 static void  virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused)
 {
+	struct rte_mbuf *pkt = NULL;
+	struct virtual_ethdev_private *prv = eth_dev->data->dev_private;
+
 	eth_dev->data->dev_link.link_status = 0;
 	eth_dev->data->dev_started = 0;
+	while (rte_ring_dequeue(prv->rx_queue, (void **)&pkt) != -ENOENT)
+		rte_pktmbuf_free(pkt);
+
+	while (rte_ring_dequeue(prv->tx_queue, (void **)&pkt) != -ENOENT)
+		rte_pktmbuf_free(pkt);
 }
 
 static void
@@ -214,8 +223,10 @@ static void
 virtual_ethdev_stats_reset(struct rte_eth_dev *dev)
 {
 	struct virtual_ethdev_private *dev_private = dev->data->dev_private;
+	struct rte_mbuf *pkt = NULL;
 
-	dev_private->rx_pkt_burst_len = 0;
+	while (rte_ring_dequeue(dev_private->tx_queue, (void **)&pkt) == -ENOBUFS)
+			rte_pktmbuf_free(pkt);
 
 	/* Reset internal statistics */
 	memset(&dev_private->eth_stats, 0, sizeof(dev_private->eth_stats));
@@ -318,29 +329,23 @@ virtual_ethdev_rx_burst_success(void *queue __rte_unused,
 	struct virtual_ethdev_queue *pq_map;
 	struct virtual_ethdev_private *dev_private;
 
-	int i;
+	int rx_count, 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) {
+	rx_count = rte_ring_dequeue_burst(dev_private->rx_queue, (void **) bufs,
+			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;
-			}
+	/* increments ipackets count */
+	dev_private->eth_stats.ipackets += rx_count;
 
-			dev_private->eth_stats.ipackets = dev_private->rx_pkt_burst_len;
-		}
-		/* reset private burst values */
-		dev_private->rx_pkt_burst_len = 0;
-	}
+	/* increments ibytes count */
+	for (i = 0; i < rx_count; i++)
+		dev_private->eth_stats.ibytes += rte_pktmbuf_pkt_len(bufs[i]);
 
-	return dev_private->eth_stats.ipackets;
+	return rx_count;
 }
 
 static uint16_t
@@ -359,26 +364,25 @@ virtual_ethdev_tx_burst_success(void *queue, struct rte_mbuf **bufs,
 
 	struct rte_eth_dev *vrtl_eth_dev;
 	struct virtual_ethdev_private *dev_private;
-	uint64_t obytes = 0;
+
 	int i;
 
-	for (i = 0; i < nb_pkts; i++)
-		obytes += rte_pktmbuf_pkt_len(bufs[i]);
 	vrtl_eth_dev = &rte_eth_devices[tx_q->port_id];
 	dev_private = vrtl_eth_dev->data->dev_private;
 
-	if (vrtl_eth_dev->data->dev_link.link_status) {
-		/* increment opacket count */
-		dev_private->eth_stats.opackets += nb_pkts;
-		dev_private->eth_stats.obytes += obytes;
-		/* free packets in burst */
-		for (i = 0; i < nb_pkts; i++)
-			rte_pktmbuf_free(bufs[i]);
+	if (!vrtl_eth_dev->data->dev_link.link_status)
+		nb_pkts = 0;
+	else
+		nb_pkts = rte_ring_enqueue_burst(dev_private->tx_queue, (void **)bufs, nb_pkts);
 
-		return nb_pkts;
-	}
+	/* increment opacket count */
+	dev_private->eth_stats.opackets += nb_pkts;
 
-	return 0;
+	/* increment obytes count */
+	for (i = 0; i < nb_pkts; i++)
+		dev_private->eth_stats.obytes += rte_pktmbuf_pkt_len(bufs[i]);
+
+	return nb_pkts;
 }
 
 static uint16_t
@@ -476,23 +480,25 @@ virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
 	_rte_eth_dev_callback_process(vrtl_eth_dev, RTE_ETH_EVENT_INTR_LSC);
 }
 
-
-
-void
+int
 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];
+	struct virtual_ethdev_private *dev_private = vrtl_eth_dev->data->dev_private;
+	return rte_ring_enqueue_burst(dev_private->rx_queue, (void **)pkt_burst, burst_length);
+}
 
-	int i;
+int
+virtual_ethdev_get_mbufs_from_tx_queue(uint8_t port_id,
+		struct rte_mbuf **pkt_burst, int burst_length)
+{
+	struct virtual_ethdev_private *dev_private;
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
 
 	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;
+	return rte_ring_dequeue_burst(dev_private->tx_queue, (void **)pkt_burst,
+		burst_length);
 }
 
 static uint8_t
@@ -510,7 +516,6 @@ get_number_of_sockets(void)
 	return ++sockets;
 }
 
-
 int
 virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 		uint8_t socket_id, uint8_t isr_support)
@@ -522,6 +527,7 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 	struct eth_dev_ops *dev_ops = NULL;
 	struct rte_pci_id *id_table = NULL;
 	struct virtual_ethdev_private *dev_private = NULL;
+	char name_buf[RTE_RING_NAMESIZE];
 
 
 	/* now do all data allocation - for eth_dev structure, dummy pci driver
@@ -555,6 +561,18 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 	if (dev_private == NULL)
 		goto err;
 
+	memset(dev_private, 0, sizeof(*dev_private));
+
+	snprintf(name_buf, sizeof(name_buf), "%s_rxQ", name);
+	dev_private->rx_queue = rte_ring_create(name_buf, MAX_PKT_BURST, socket_id, 0);
+	if (dev_private->rx_queue == NULL)
+		goto err;
+
+	snprintf(name_buf, sizeof(name_buf), "%s_txQ", name);
+	dev_private->tx_queue = rte_ring_create(name_buf, MAX_PKT_BURST, socket_id, 0);
+	if (dev_private->tx_queue == NULL)
+		goto err;
+
 	/* reserve an ethdev entry */
 	eth_dev = rte_eth_dev_allocate(name);
 	if (eth_dev == NULL)
@@ -594,7 +612,6 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 	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;
diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h
index 2462853..de00188 100644
--- a/app/test/virtual_pmd.h
+++ b/app/test/virtual_pmd.h
@@ -54,10 +54,13 @@ void
 virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
 		uint8_t link_status);
 
-void
+int
 virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id,
 		struct rte_mbuf **pkts_burst, int burst_length);
 
+int
+virtual_ethdev_get_mbufs_from_tx_queue(uint8_t port_id,
+		struct rte_mbuf **pkt_burst, int burst_length);
 
 /** Control methods for the dev_ops functions pointer to control the behavior
  *  of the Virtual PMD */
-- 
1.7.9.5

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

* Re: [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB)
  2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                   ` (5 preceding siblings ...)
  2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 6/6] bond: add unit tests for link bonding mode 6 Michal Jastrzebski
@ 2015-02-13 16:12 ` Declan Doherty
  2015-02-18 19:10   ` Thomas Monjalon
  2015-02-19 17:26 ` [dpdk-dev] [PATCH v3 " Michal Jastrzebski
  2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
  8 siblings, 1 reply; 35+ messages in thread
From: Declan Doherty @ 2015-02-13 16:12 UTC (permalink / raw)
  To: Michal Jastrzebski, dev

On 13/02/15 15:16, Michal Jastrzebski wrote:
> This patchset add support for link bonding mode 6.
> Additionally it changes an arp_header structure definition.
> Also a basic example is introduced. Using this example,
> Bonding will configure each client ARP table,
> that packets from each client will be received on different slave,
> mode 6 uses round-robin policy to assign slave to client IP address.
>
> Michal Jastrzebski (6):
>    net: changed arp_hdr struct declaration
>    bond: add link bonding mode 6 implementation
>    bond: add debug info for mode 6 link bonding
>    bond: add example application for link bonding mode 6
>    bond: modify TLB unit tests
>    bond: add unit tests for link bonding mode 6.
>
>   app/test-pmd/icmpecho.c                    |   27 +-
>   app/test/packet_burst_generator.c          |   41 +-
>   app/test/packet_burst_generator.h          |   11 +-
>   app/test/test_link_bonding.c               |  422 ++++++++++++++-
>   app/test/test_pmd_perf.c                   |    3 +-
>   app/test/virtual_pmd.c                     |  103 ++--
>   app/test/virtual_pmd.h                     |    5 +-
>   config/common_linuxapp                     |    3 +-
>   examples/bond/Makefile                     |   57 ++
>   examples/bond/main.c                       |  792 ++++++++++++++++++++++++++++
>   examples/bond/main.h                       |   46 ++
>   lib/librte_net/rte_arp.h                   |   13 +-
>   lib/librte_pmd_bond/Makefile               |    1 +
>   lib/librte_pmd_bond/rte_eth_bond.h         |   11 +-
>   lib/librte_pmd_bond/rte_eth_bond_alb.c     |  256 +++++++++
>   lib/librte_pmd_bond/rte_eth_bond_alb.h     |  109 ++++
>   lib/librte_pmd_bond/rte_eth_bond_api.c     |   28 +-
>   lib/librte_pmd_bond/rte_eth_bond_args.c    |    3 +-
>   lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  460 ++++++++++++++--
>   lib/librte_pmd_bond/rte_eth_bond_private.h |   12 +
>   20 files changed, 2257 insertions(+), 146 deletions(-)
>   create mode 100644 examples/bond/Makefile
>   create mode 100644 examples/bond/main.c
>   create mode 100644 examples/bond/main.h
>   create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c
>   create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h
>

Series Acked-by: Declan Doherty <declan.doherty@intel.com>

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

* Re: [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB)
  2015-02-13 16:12 ` [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Declan Doherty
@ 2015-02-18 19:10   ` Thomas Monjalon
  2015-02-19  9:18     ` Jastrzebski, MichalX K
  0 siblings, 1 reply; 35+ messages in thread
From: Thomas Monjalon @ 2015-02-18 19:10 UTC (permalink / raw)
  To: Declan Doherty, Michal Jastrzebski; +Cc: dev

Hi,

2015-02-13 16:12, Declan Doherty:
> On 13/02/15 15:16, Michal Jastrzebski wrote:
> > Michal Jastrzebski (6):
> >    net: changed arp_hdr struct declaration
> >    bond: add link bonding mode 6 implementation
> >    bond: add debug info for mode 6 link bonding
> >    bond: add example application for link bonding mode 6
> >    bond: modify TLB unit tests
> >    bond: add unit tests for link bonding mode 6.

You didn't sign some of these patches. So I suspect that you should
fix some authorship.

Some of the patches make some changes without explaining why.

> Series Acked-by: Declan Doherty <declan.doherty@intel.com>

Please, use checkpatch before submitting and/or when reviewing.

A v3 is needed.

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

* Re: [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB)
  2015-02-18 19:10   ` Thomas Monjalon
@ 2015-02-19  9:18     ` Jastrzebski, MichalX K
  2015-02-19  9:39       ` Thomas Monjalon
  0 siblings, 1 reply; 35+ messages in thread
From: Jastrzebski, MichalX K @ 2015-02-19  9:18 UTC (permalink / raw)
  To: Thomas Monjalon, Doherty, Declan; +Cc: dev

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, February 18, 2015 8:10 PM
> To: Doherty, Declan; Jastrzebski, MichalX K
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB)
> 
> Hi,
> 
> 2015-02-13 16:12, Declan Doherty:
> > On 13/02/15 15:16, Michal Jastrzebski wrote:
> > > Michal Jastrzebski (6):
> > >    net: changed arp_hdr struct declaration
> > >    bond: add link bonding mode 6 implementation
> > >    bond: add debug info for mode 6 link bonding
> > >    bond: add example application for link bonding mode 6
> > >    bond: modify TLB unit tests
> > >    bond: add unit tests for link bonding mode 6.
> 
Hi Thomas,
> You didn't sign some of these patches. So I suspect that you should
> fix some authorship.
That's because I am not an author of all of these patches - 1/6, 5/6 and 6/6
> 
> Some of the patches make some changes without explaining why.
I noticed 5/6 has got incomplete description. Probably it disappeared during edition.
> 
> > Series Acked-by: Declan Doherty <declan.doherty@intel.com>
> 
> Please, use checkpatch before submitting and/or when reviewing.
I was using checkptach.pl, and have no errors, but I will check again.
Maybe I overlooked something.
> 
> A v3 is needed.

Best regards
Michal

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

* Re: [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB)
  2015-02-19  9:18     ` Jastrzebski, MichalX K
@ 2015-02-19  9:39       ` Thomas Monjalon
  2015-02-19 10:14         ` Jastrzebski, MichalX K
  0 siblings, 1 reply; 35+ messages in thread
From: Thomas Monjalon @ 2015-02-19  9:39 UTC (permalink / raw)
  To: Jastrzebski, MichalX K; +Cc: dev

2015-02-19 09:18, Jastrzebski, MichalX K:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > 2015-02-13 16:12, Declan Doherty:
> > > On 13/02/15 15:16, Michal Jastrzebski wrote:
> > > > Michal Jastrzebski (6):
> > > >    net: changed arp_hdr struct declaration
> > > >    bond: add link bonding mode 6 implementation
> > > >    bond: add debug info for mode 6 link bonding
> > > >    bond: add example application for link bonding mode 6
> > > >    bond: modify TLB unit tests
> > > >    bond: add unit tests for link bonding mode 6.
> > 
> Hi Thomas,
> > You didn't sign some of these patches. So I suspect that you should
> > fix some authorship.
> That's because I am not an author of all of these patches - 1/6, 5/6 and 6/6

You probably broke it by importing patches with "patch" command instead of "git am".
Then you must fix the authorship in your git tree before sending.

> > Some of the patches make some changes without explaining why.
> I noticed 5/6 has got incomplete description. Probably it disappeared during edition.

Yes please ask yourself why each patch is done, and check it's explained in commit log.

> > > Series Acked-by: Declan Doherty <declan.doherty@intel.com>
> > 
> > Please, use checkpatch before submitting and/or when reviewing.
> I was using checkptach.pl, and have no errors, but I will check again.
> Maybe I overlooked something.
> > 
> > A v3 is needed.
> 
> Best regards
> Michal

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

* Re: [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB)
  2015-02-19  9:39       ` Thomas Monjalon
@ 2015-02-19 10:14         ` Jastrzebski, MichalX K
  2015-02-19 10:27           ` Thomas Monjalon
  0 siblings, 1 reply; 35+ messages in thread
From: Jastrzebski, MichalX K @ 2015-02-19 10:14 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Thursday, February 19, 2015 10:40 AM
> To: Jastrzebski, MichalX K
> Cc: Doherty, Declan; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB)
> 
> 2015-02-19 09:18, Jastrzebski, MichalX K:
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > 2015-02-13 16:12, Declan Doherty:
> > > > On 13/02/15 15:16, Michal Jastrzebski wrote:
> > > > > Michal Jastrzebski (6):
> > > > >    net: changed arp_hdr struct declaration
> > > > >    bond: add link bonding mode 6 implementation
> > > > >    bond: add debug info for mode 6 link bonding
> > > > >    bond: add example application for link bonding mode 6
> > > > >    bond: modify TLB unit tests
> > > > >    bond: add unit tests for link bonding mode 6.
> > >
> > Hi Thomas,
> > > You didn't sign some of these patches. So I suspect that you should
> > > fix some authorship.
> > That's because I am not an author of all of these patches - 1/6, 5/6 and 6/6
> 
> You probably broke it by importing patches with "patch" command instead of
> "git am".
> Then you must fix the authorship in your git tree before sending.
The authorship in v2 is proper as I think I shouldn't signoff patch that is not mine
-  that I was never working on the code it provides, should I? 
I edited the patches manually before I submitted it to match the proper authority,
In git tree I have all patches signed-off by myself by default.
> 
> > > Some of the patches make some changes without explaining why.
> > I noticed 5/6 has got incomplete description. Probably it disappeared
> during edition.
> 
> Yes please ask yourself why each patch is done, and check it's explained in
> commit log.
> 
> > > > Series Acked-by: Declan Doherty <declan.doherty@intel.com>
> > >
> > > Please, use checkpatch before submitting and/or when reviewing.
> > I was using checkptach.pl, and have no errors, but I will check again.
> > Maybe I overlooked something.
> > >
> > > A v3 is needed.
> >
> > Best regards
> > Michal

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

* Re: [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB)
  2015-02-19 10:14         ` Jastrzebski, MichalX K
@ 2015-02-19 10:27           ` Thomas Monjalon
  0 siblings, 0 replies; 35+ messages in thread
From: Thomas Monjalon @ 2015-02-19 10:27 UTC (permalink / raw)
  To: Jastrzebski, MichalX K; +Cc: dev

2015-02-19 10:14, Jastrzebski, MichalX K:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > 2015-02-19 09:18, Jastrzebski, MichalX K:
> > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > > 2015-02-13 16:12, Declan Doherty:
> > > > > On 13/02/15 15:16, Michal Jastrzebski wrote:
> > > > > > Michal Jastrzebski (6):
> > > > > >    net: changed arp_hdr struct declaration
> > > > > >    bond: add link bonding mode 6 implementation
> > > > > >    bond: add debug info for mode 6 link bonding
> > > > > >    bond: add example application for link bonding mode 6
> > > > > >    bond: modify TLB unit tests
> > > > > >    bond: add unit tests for link bonding mode 6.
> > > >
> > > Hi Thomas,
> > > > You didn't sign some of these patches. So I suspect that you should
> > > > fix some authorship.
> > > That's because I am not an author of all of these patches - 1/6, 5/6 and 6/6
> > 
> > You probably broke it by importing patches with "patch" command instead of
> > "git am".
> > Then you must fix the authorship in your git tree before sending.
> 
> The authorship in v2 is proper as I think I shouldn't signoff patch that is not mine
> -  that I was never working on the code it provides, should I? 

No. Signed-off is about responsibility of a patch.
I'm speaking about authorship. Please use "git log" and check what is the
name after "Author: ". There is also authoring date but it's not important.
When sending email, the Author field is converted in a From field.

> I edited the patches manually before I submitted it to match the proper authority,
> In git tree I have all patches signed-off by myself by default.

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

* [dpdk-dev] [PATCH v3 0/6] Link Bonding mode 6 support (ALB)
  2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                   ` (6 preceding siblings ...)
  2015-02-13 16:12 ` [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Declan Doherty
@ 2015-02-19 17:26 ` Michal Jastrzebski
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
                     ` (5 more replies)
  2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
  8 siblings, 6 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-19 17:26 UTC (permalink / raw)
  To: dev

v3 changes:
- completed description for mode 5 unit tests patch
- fixed errors required by checkpatch.pl
- moved patch version changes from patches to cover-letter

v2 changes:
in mode 6 patch 2/6:
- add VLAN support
- fixed sending duplicated ARPupdates
- fixed assigning slaves for next clients
- fixed TLB mode

in debug patch 3/6:
- add IPv4 RX/TX information
- add mode6_debug(..) function

in the example application patch 4/6:
- remove count parameter from send command
- fixed quit command to use cmdline_quit(cl)
- add echo function - all IPv4 packets will be retransmitted. Bonding
	driver will use TLB policy - this will show how TX works in mode 6
- remove unused structures rx_conf_default and tx_conf_default
- add VLAN support
- remove unnecessary comments
- nodify show command in term of printing DEBUG informations

This patchset add support for link bonding mode 6.
Additionally it changes an arp_header structure definition.
Also a basic example is introduced. Using this example,
Bonding will configure each client ARP table,
that packets from each client will be received on different slave,
mode 6 uses round-robin policy to assign slave to client IP address.

Daniel Mrzyglod (1):
  bond: modify TLB unit tests

Maciej Gajdzica (3):
  net: changed arp_hdr struct declaration
  bond: add link bonding mode 6 implementation
  bond: add unit tests for link bonding mode 6.

Michal Jastrzebski (2):
  bond: add debug info for mode 6 link bonding
  bond: add example application for link bonding mode 6

 app/test-pmd/icmpecho.c                    |   27 +-
 app/test/packet_burst_generator.c          |   41 +-
 app/test/packet_burst_generator.h          |   11 +-
 app/test/test_link_bonding.c               |  450 +++++++++++++++-
 app/test/test_pmd_perf.c                   |    3 +-
 app/test/virtual_pmd.c                     |  109 ++--
 app/test/virtual_pmd.h                     |    5 +-
 config/common_linuxapp                     |    3 +-
 examples/bond/Makefile                     |   57 ++
 examples/bond/main.c                       |  796 ++++++++++++++++++++++++++++
 examples/bond/main.h                       |   46 ++
 lib/librte_net/rte_arp.h                   |   13 +-
 lib/librte_pmd_bond/Makefile               |    1 +
 lib/librte_pmd_bond/rte_eth_bond.h         |   11 +-
 lib/librte_pmd_bond/rte_eth_bond_alb.c     |  256 +++++++++
 lib/librte_pmd_bond/rte_eth_bond_alb.h     |  109 ++++
 lib/librte_pmd_bond/rte_eth_bond_api.c     |   28 +-
 lib/librte_pmd_bond/rte_eth_bond_args.c    |    3 +-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  460 ++++++++++++++--
 lib/librte_pmd_bond/rte_eth_bond_private.h |   12 +
 20 files changed, 2295 insertions(+), 146 deletions(-)
 create mode 100644 examples/bond/Makefile
 create mode 100644 examples/bond/main.c
 create mode 100644 examples/bond/main.h
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h

-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v3 1/6] net: changed arp_hdr struct declaration
  2015-02-19 17:26 ` [dpdk-dev] [PATCH v3 " Michal Jastrzebski
@ 2015-02-19 17:26   ` Michal Jastrzebski
  2015-02-20 14:30     ` Thomas Monjalon
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 2/6] bond: add link bonding mode 6 implementation Michal Jastrzebski
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-19 17:26 UTC (permalink / raw)
  To: dev

From: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>

Changed MAC address type from uint8_t[6] to struct ether_addr and IP
address type from uint8_t[4] to uint32_t. Also removed union from
arp_hdr struct. Updated test-pmd to match new arp_hdr version.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
---
 app/test-pmd/icmpecho.c  |   27 ++++++++++-----------------
 lib/librte_net/rte_arp.h |   13 ++++++-------
 2 files changed, 16 insertions(+), 24 deletions(-)

diff --git a/app/test-pmd/icmpecho.c b/app/test-pmd/icmpecho.c
index 08ea01d..010c5a9 100644
--- a/app/test-pmd/icmpecho.c
+++ b/app/test-pmd/icmpecho.c
@@ -371,18 +371,14 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 				continue;
 			}
 			if (verbose_level > 0) {
-				memcpy(&eth_addr,
-				       arp_h->arp_data.arp_ip.arp_sha, 6);
+				ether_addr_copy(&arp_h->arp_data.arp_sha, &eth_addr);
 				ether_addr_dump("        sha=", &eth_addr);
-				memcpy(&ip_addr,
-				       arp_h->arp_data.arp_ip.arp_sip, 4);
+				ip_addr = arp_h->arp_data.arp_sip;
 				ipv4_addr_dump(" sip=", ip_addr);
 				printf("\n");
-				memcpy(&eth_addr,
-				       arp_h->arp_data.arp_ip.arp_tha, 6);
+				ether_addr_copy(&arp_h->arp_data.arp_tha, &eth_addr);
 				ether_addr_dump("        tha=", &eth_addr);
-				memcpy(&ip_addr,
-				       arp_h->arp_data.arp_ip.arp_tip, 4);
+				ip_addr = arp_h->arp_data.arp_tip;
 				ipv4_addr_dump(" tip=", ip_addr);
 				printf("\n");
 			}
@@ -402,17 +398,14 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 					&eth_h->s_addr);
 
 			arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
-			memcpy(&eth_addr, arp_h->arp_data.arp_ip.arp_tha, 6);
-			memcpy(arp_h->arp_data.arp_ip.arp_tha,
-			       arp_h->arp_data.arp_ip.arp_sha, 6);
-			memcpy(arp_h->arp_data.arp_ip.arp_sha,
-			       &eth_h->s_addr, 6);
+			ether_addr_copy(&arp_h->arp_data.arp_tha, &eth_addr);
+			ether_addr_copy(&arp_h->arp_data.arp_sha, &arp_h->arp_data.arp_tha);
+			ether_addr_copy(&eth_addr, &arp_h->arp_data.arp_sha);
 
 			/* Swap IP addresses in ARP payload */
-			memcpy(&ip_addr, arp_h->arp_data.arp_ip.arp_sip, 4);
-			memcpy(arp_h->arp_data.arp_ip.arp_sip,
-			       arp_h->arp_data.arp_ip.arp_tip, 4);
-			memcpy(arp_h->arp_data.arp_ip.arp_tip, &ip_addr, 4);
+			ip_addr = arp_h->arp_data.arp_sip;
+			arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
+			arp_h->arp_data.arp_tip = ip_addr;
 			pkts_burst[nb_replies++] = pkt;
 			continue;
 		}
diff --git a/lib/librte_net/rte_arp.h b/lib/librte_net/rte_arp.h
index c7b0e51..72108a1 100644
--- a/lib/librte_net/rte_arp.h
+++ b/lib/librte_net/rte_arp.h
@@ -39,6 +39,7 @@
  */
 
 #include <stdint.h>
+#include <rte_ether.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -48,10 +49,10 @@ extern "C" {
  * ARP header IPv4 payload.
  */
 struct arp_ipv4 {
-	uint8_t  arp_sha[6]; /* sender hardware address */
-	uint8_t  arp_sip[4]; /* sender IP address */
-	uint8_t  arp_tha[6]; /* target hardware address */
-	uint8_t  arp_tip[4]; /* target IP address */
+	struct ether_addr  arp_sha;	/* sender hardware address */
+	uint32_t  arp_sip;			/* sender IP address */
+	struct ether_addr  arp_tha;	/* target hardware address */
+	uint32_t  arp_tip;			/* target IP address */
 } __attribute__((__packed__));
 
 /**
@@ -72,9 +73,7 @@ struct arp_hdr {
 #define	ARP_OP_INVREQUEST 8 /* request to identify peer */
 #define	ARP_OP_INVREPLY   9 /* response identifying peer */
 
-	union {
-		struct arp_ipv4 arp_ip;
-	} arp_data;
+	struct arp_ipv4 arp_data;
 } __attribute__((__packed__));
 
 #ifdef __cplusplus
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v3 2/6] bond: add link bonding mode 6 implementation
  2015-02-19 17:26 ` [dpdk-dev] [PATCH v3 " Michal Jastrzebski
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
@ 2015-02-19 17:26   ` Michal Jastrzebski
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 3/6] bond: add debug info for mode 6 link bonding Michal Jastrzebski
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-19 17:26 UTC (permalink / raw)
  To: dev

From: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>

This mode includes adaptive TLB and receive load balancing (RLB). In RLB
the bonding driver intercepts ARP replies send by local system and
overwrites its source MAC address, so that different peers send data to
the server on different slave interfaces. When local system sends ARP
request, it saves IP information from it. When ARP reply from that peer
is received, its MAC is stored, one of slave MACs assigned and ARP reply
send to that peer.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
Signed-off-by: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
---
 lib/librte_pmd_bond/Makefile               |    1 +
 lib/librte_pmd_bond/rte_eth_bond.h         |    9 +
 lib/librte_pmd_bond/rte_eth_bond_alb.c     |  256 +++++++++++++++++++++++++++
 lib/librte_pmd_bond/rte_eth_bond_alb.h     |  109 ++++++++++++
 lib/librte_pmd_bond/rte_eth_bond_api.c     |   28 ++-
 lib/librte_pmd_bond/rte_eth_bond_args.c    |    1 +
 lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  259 ++++++++++++++++++++++++----
 lib/librte_pmd_bond/rte_eth_bond_private.h |   12 ++
 8 files changed, 640 insertions(+), 35 deletions(-)
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h

diff --git a/lib/librte_pmd_bond/Makefile b/lib/librte_pmd_bond/Makefile
index d6c81a8..cb16356 100644
--- a/lib/librte_pmd_bond/Makefile
+++ b/lib/librte_pmd_bond/Makefile
@@ -50,6 +50,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_api.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_pmd.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_8023ad.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_alb.c
 
 ifeq ($(CONFIG_RTE_MBUF_REFCNT),n)
 $(info WARNING: Link Bonding Broadcast mode is disabled because it needs MBUF_REFCNT.)
diff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h
index 7177983..13581cb 100644
--- a/lib/librte_pmd_bond/rte_eth_bond.h
+++ b/lib/librte_pmd_bond/rte_eth_bond.h
@@ -101,6 +101,15 @@ extern "C" {
  * This mode provides an adaptive transmit load balancing. It dynamically
  * changes the transmitting slave, according to the computed load. Statistics
  * are collected in 100ms intervals and scheduled every 10ms */
+#define BONDING_MODE_ALB	(6)
+/**< Adaptive Load Balancing (Mode 6)
+ * This mode includes adaptive TLB and receive load balancing (RLB). In RLB the
+ * bonding driver intercepts ARP replies send by local system and overwrites its
+ * source MAC address, so that different peers send data to the server on
+ * different slave interfaces. When local system sends ARP request, it saves IP
+ * information from it. When ARP reply from that peer is received, its MAC is
+ * stored, one of slave MACs assigned and ARP reply send to that peer.
+ */
 
 /* Balance Mode Transmit Policies */
 #define BALANCE_XMIT_POLICY_LAYER2		(0)
diff --git a/lib/librte_pmd_bond/rte_eth_bond_alb.c b/lib/librte_pmd_bond/rte_eth_bond_alb.c
new file mode 100644
index 0000000..55ed842
--- /dev/null
+++ b/lib/librte_pmd_bond/rte_eth_bond_alb.c
@@ -0,0 +1,256 @@
+#include "rte_eth_bond_private.h"
+#include "rte_eth_bond_alb.h"
+
+static inline uint8_t
+simple_hash(uint8_t *hash_start, int hash_size)
+{
+	int i;
+	uint8_t hash;
+
+	hash = 0;
+	for (i = 0; i < hash_size; ++i)
+		hash ^= hash_start[i];
+
+	return hash;
+}
+
+static uint8_t
+calculate_slave(struct bond_dev_private *internals)
+{
+	uint8_t idx;
+
+	idx = (internals->mode6.last_slave + 1) % internals->active_slave_count;
+	internals->mode6.last_slave = idx;
+	return internals->active_slaves[idx];
+}
+
+int
+bond_mode_alb_enable(struct rte_eth_dev *bond_dev)
+{
+	struct bond_dev_private *internals = bond_dev->data->dev_private;
+	struct client_data *hash_table = internals->mode6.client_table;
+
+	uint16_t element_size;
+	char mem_name[RTE_ETH_NAME_MAX_LEN];
+	int socket_id = bond_dev->pci_dev->numa_node;
+
+	/* Fill hash table with initial values */
+	memset(hash_table, 0, sizeof(struct client_data) * ALB_HASH_TABLE_SIZE);
+	rte_spinlock_init(&internals->mode6.lock);
+	internals->mode6.last_slave = ALB_NULL_INDEX;
+	internals->mode6.ntt = 0;
+
+	/* Initialize memory pool for ARP packets to send */
+	if (internals->mode6.mempool == NULL) {
+		/*
+		 * 256 is size of ETH header, ARP header and nested VLAN headers.
+		 * The value is chosen to be cache aligned.
+		 */
+		element_size = 256 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM;
+		snprintf(mem_name, sizeof(mem_name), "%s_MODE6", bond_dev->data->name);
+		internals->mode6.mempool = rte_mempool_create(mem_name,
+				512 * RTE_MAX_ETHPORTS,
+				element_size,
+				RTE_MEMPOOL_CACHE_MAX_SIZE >= 32 ?
+						32 : RTE_MEMPOOL_CACHE_MAX_SIZE,
+				sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init,
+				NULL, rte_pktmbuf_init, NULL, socket_id, 0);
+
+		if (internals->mode6.mempool == NULL) {
+			RTE_LOG(ERR, PMD, "%s: Failed to initialize ALB mempool.\n",
+					bond_dev->data->name);
+			rte_panic(
+					"Failed to alocate memory pool ('%s')\n"
+					"for bond device '%s'\n",
+					mem_name, bond_dev->data->name);
+		}
+	}
+
+	return 0;
+}
+
+void bond_mode_alb_arp_recv(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals) {
+	struct arp_hdr *arp;
+
+	struct client_data *hash_table = internals->mode6.client_table;
+	struct client_data *client_info;
+
+	uint8_t hash_index;
+
+	arp = (struct arp_hdr *) ((char *) (eth_h + 1) + offset);
+
+	/* ARP Requests are forwarded to the application with no changes */
+	if (arp->arp_op != rte_cpu_to_be_16(ARP_OP_REPLY))
+		return;
+
+	/* From now on, we analyze only ARP Reply packets */
+	hash_index = simple_hash((uint8_t *) &arp->arp_data.arp_sip,
+			sizeof(arp->arp_data.arp_sip));
+	client_info = &hash_table[hash_index];
+
+	/*
+	 * We got reply for ARP Request send by the application. We need to
+	 * update client table when received data differ from what is stored
+	 * in ALB table and issue sending update packet to that slave.
+	 */
+	rte_spinlock_lock(&internals->mode6.lock);
+	if (client_info->in_use == 0 ||
+			client_info->app_ip != arp->arp_data.arp_tip ||
+			client_info->cli_ip != arp->arp_data.arp_sip ||
+			!is_same_ether_addr(&client_info->cli_mac, &arp->arp_data.arp_sha) ||
+			client_info->vlan_count != offset / sizeof(struct vlan_hdr) ||
+			memcmp(client_info->vlan, eth_h + 1, offset) != 0
+	) {
+		client_info->in_use = 1;
+		client_info->app_ip = arp->arp_data.arp_tip;
+		client_info->cli_ip = arp->arp_data.arp_sip;
+		ether_addr_copy(&arp->arp_data.arp_sha, &client_info->cli_mac);
+		client_info->slave_idx = calculate_slave(internals);
+		rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+		ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_tha);
+		memcpy(client_info->vlan, eth_h + 1, offset);
+		client_info->vlan_count = offset / sizeof(struct vlan_hdr);
+	}
+	internals->mode6.ntt = 1;
+	rte_spinlock_unlock(&internals->mode6.lock);
+}
+
+uint8_t
+bond_mode_alb_arp_xmit(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals)
+{
+	struct arp_hdr *arp;
+
+	struct client_data *hash_table = internals->mode6.client_table;
+	struct client_data *client_info;
+
+	uint8_t hash_index;
+
+	struct ether_addr bonding_mac;
+
+	arp = (struct arp_hdr *)((char *)(eth_h + 1) + offset);
+
+	/*
+	 * Traffic with src MAC other than bonding should be sent on
+	 * current primary port.
+	 */
+	rte_eth_macaddr_get(internals->port_id, &bonding_mac);
+	if (!is_same_ether_addr(&bonding_mac, &arp->arp_data.arp_sha)) {
+		rte_eth_macaddr_get(internals->current_primary_port,
+				&arp->arp_data.arp_sha);
+		return internals->current_primary_port;
+	}
+
+	hash_index = simple_hash((uint8_t *)&arp->arp_data.arp_tip,
+			sizeof(uint32_t));
+	client_info = &hash_table[hash_index];
+
+	rte_spinlock_lock(&internals->mode6.lock);
+	if (arp->arp_op == rte_cpu_to_be_16(ARP_OP_REPLY)) {
+		if (client_info->in_use) {
+			if (client_info->app_ip == arp->arp_data.arp_sip &&
+				client_info->cli_ip == arp->arp_data.arp_tip) {
+				/* Entry is already assigned to this client */
+				if (!is_broadcast_ether_addr(&arp->arp_data.arp_tha)) {
+					ether_addr_copy(&arp->arp_data.arp_tha,
+							&client_info->cli_mac);
+				}
+				rte_eth_macaddr_get(client_info->slave_idx,
+						&client_info->app_mac);
+				ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);
+				memcpy(client_info->vlan, eth_h + 1, offset);
+				client_info->vlan_count = offset / sizeof(struct vlan_hdr);
+				rte_spinlock_unlock(&internals->mode6.lock);
+				return client_info->slave_idx;
+			}
+		}
+
+		/* Assign new slave to this client and update src mac in ARP */
+		client_info->in_use = 1;
+		client_info->ntt = 0;
+		client_info->app_ip = arp->arp_data.arp_sip;
+		ether_addr_copy(&arp->arp_data.arp_tha, &client_info->cli_mac);
+		client_info->cli_ip = arp->arp_data.arp_tip;
+		client_info->slave_idx = calculate_slave(internals);
+		rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+		ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);
+		memcpy(client_info->vlan, eth_h + 1, offset);
+		client_info->vlan_count = offset / sizeof(struct vlan_hdr);
+		rte_spinlock_unlock(&internals->mode6.lock);
+		return client_info->slave_idx;
+	}
+
+	/* If packet is not ARP Reply, send it on current primary port. */
+	rte_spinlock_unlock(&internals->mode6.lock);
+	rte_eth_macaddr_get(internals->current_primary_port,
+			&arp->arp_data.arp_sha);
+	return internals->current_primary_port;
+}
+
+uint8_t
+bond_mode_alb_arp_upd(struct client_data *client_info,
+		struct rte_mbuf *pkt, struct bond_dev_private *internals)
+{
+	struct ether_hdr *eth_h;
+	struct arp_hdr *arp_h;
+	uint8_t slave_idx;
+
+	rte_spinlock_lock(&internals->mode6.lock);
+	eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+
+	ether_addr_copy(&client_info->app_mac, &eth_h->s_addr);
+	ether_addr_copy(&client_info->cli_mac, &eth_h->d_addr);
+	if (client_info->vlan_count > 0)
+		eth_h->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	else
+		eth_h->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+
+	arp_h = (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr)
+			+ client_info->vlan_count * sizeof(struct vlan_hdr));
+
+	memcpy(eth_h + 1, client_info->vlan,
+			client_info->vlan_count * sizeof(struct vlan_hdr));
+
+	ether_addr_copy(&client_info->app_mac, &arp_h->arp_data.arp_sha);
+	arp_h->arp_data.arp_sip = client_info->app_ip;
+	ether_addr_copy(&client_info->cli_mac, &arp_h->arp_data.arp_tha);
+	arp_h->arp_data.arp_tip = client_info->cli_ip;
+
+	arp_h->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
+	arp_h->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	arp_h->arp_hln = ETHER_ADDR_LEN;
+	arp_h->arp_pln = sizeof(uint32_t);
+	arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
+
+	slave_idx = client_info->slave_idx;
+	rte_spinlock_unlock(&internals->mode6.lock);
+
+	return slave_idx;
+}
+
+void
+bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev)
+{
+	struct bond_dev_private *internals = bond_dev->data->dev_private;
+	struct client_data *client_info;
+
+	int i;
+
+	/* If active slave count is 0, it's pointless to refresh alb table */
+	if (internals->active_slave_count <= 0)
+		return;
+
+	rte_spinlock_lock(&internals->mode6.lock);
+	internals->mode6.last_slave = ALB_NULL_INDEX;
+
+	for (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {
+		client_info = &internals->mode6.client_table[i];
+		if (client_info->in_use) {
+			client_info->slave_idx = calculate_slave(internals);
+			rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+			internals->mode6.ntt = 1;
+		}
+	}
+	rte_spinlock_unlock(&internals->mode6.lock);
+}
diff --git a/lib/librte_pmd_bond/rte_eth_bond_alb.h b/lib/librte_pmd_bond/rte_eth_bond_alb.h
new file mode 100644
index 0000000..0cfe942
--- /dev/null
+++ b/lib/librte_pmd_bond/rte_eth_bond_alb.h
@@ -0,0 +1,109 @@
+#ifndef RTE_ETH_BOND_ALB_H_
+#define RTE_ETH_BOND_ALB_H_
+
+#include <rte_ether.h>
+#include <rte_arp.h>
+
+#define ALB_HASH_TABLE_SIZE	256
+#define ALB_NULL_INDEX		0xFFFFFFFF
+
+struct client_data {
+	/** ARP data of single client */
+	struct ether_addr app_mac;
+	/**< MAC address of application running DPDK */
+	uint32_t app_ip;
+	/**< IP address of application running DPDK */
+	struct ether_addr cli_mac;
+	/**< Client MAC address */
+	uint32_t cli_ip;
+	/**< Client IP address */
+
+	uint8_t slave_idx;
+	/**< Index of slave on which we connect with that client */
+	uint8_t in_use;
+	/**< Flag indicating if entry in client table is currently used */
+	uint8_t ntt;
+	/**< Flag indicating if we need to send update to this client on next tx */
+
+	struct vlan_hdr vlan[2];
+	/**< Content of vlan headers */
+	uint8_t vlan_count;
+	/**< Number of nested vlan headers */
+};
+
+struct mode_alb_private {
+	struct client_data client_table[ALB_HASH_TABLE_SIZE];
+	/**< Hash table storing ARP data of every client connected */
+	struct rte_mempool *mempool;
+	/**< Mempool for creating ARP update packets */
+	uint8_t ntt;
+	/**< Flag indicating if we need to send update to any client on next tx */
+	uint32_t last_slave;
+	/**< Index of last used slave in client table */
+	rte_spinlock_t lock;
+};
+
+/**
+ * ALB mode initialization.
+ *
+ * @param bond_dev		Pointer to bonding device.
+ *
+ * @return
+ * Error code - 0 on success.
+ */
+int
+bond_mode_alb_enable(struct rte_eth_dev *bond_dev);
+
+/**
+ * Function handles ARP packet reception. If received ARP request, it is
+ * forwarded to application without changes. If it is ARP reply, client table
+ * is updated.
+ *
+ * @param eth_h			ETH header of received packet.
+ * @param offset		Vlan header offset.
+ * @param internals		Bonding data.
+ */
+void
+bond_mode_alb_arp_recv(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals);
+
+/**
+ * Function handles ARP packet transmission. It also decides on which slave
+ * send that packet. If packet is ARP Request, it is send on primary slave.
+ * If it is ARP Reply, it is send on slave stored in client table for that
+ * connection. On Reply function also updates data in client table.
+ *
+ * @param eth_h			ETH header of transmitted packet.
+ * @param offset		Vlan header offset.
+ * @param internals		Bonding data.
+ *
+ * @return
+ * Index of slave on which packet should be sent.
+ */
+uint8_t
+bond_mode_alb_arp_xmit(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals);
+
+/**
+ * Function fills packet with ARP data from client_info.
+ *
+ * @param client_info	Data of client to which packet is sent.
+ * @param pkt			Pointer to packet which is sent.
+ * @param internals		Bonding data.
+ *
+ * @return
+ * Index of slawe on which packet should be sent.
+ */
+uint8_t
+bond_mode_alb_arp_upd(struct client_data *client_info,
+		struct rte_mbuf *pkt, struct bond_dev_private *internals);
+
+/**
+ * Function updates slave indexes of active connections.
+ *
+ * @param bond_dev		Pointer to bonded device struct.
+ */
+void
+bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev);
+
+#endif /* RTE_ETH_BOND_ALB_H_ */
diff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c
index 4ab3267..cbfd185 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_api.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c
@@ -111,15 +111,27 @@ void
 activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 {
 	struct bond_dev_private *internals = eth_dev->data->dev_private;
+	uint8_t active_count = internals->active_slave_count;
 
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_activate_slave(eth_dev, port_id);
 
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+			|| internals->mode == BONDING_MODE_ALB) {
+
+		internals->tlb_slaves_order[active_count] = port_id;
+	}
+
 	RTE_VERIFY(internals->active_slave_count <
 			(RTE_DIM(internals->active_slaves) - 1));
 
 	internals->active_slaves[internals->active_slave_count] = port_id;
 	internals->active_slave_count++;
+
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)
+		bond_tlb_activate_slave(internals);
+	if (internals->mode == BONDING_MODE_ALB)
+		bond_mode_alb_client_list_upd(eth_dev);
 }
 
 void
@@ -132,7 +144,9 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (internals->mode == BONDING_MODE_8023AD) {
 		bond_mode_8023ad_stop(eth_dev);
 		bond_mode_8023ad_deactivate_slave(eth_dev, port_id);
-	}
+	} else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+			|| internals->mode == BONDING_MODE_ALB)
+		bond_tlb_disable(internals);
 
 	slave_pos = find_slave_by_id(internals->active_slaves, active_count,
 			port_id);
@@ -150,8 +164,16 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	RTE_VERIFY(active_count < RTE_DIM(internals->active_slaves));
 	internals->active_slave_count = active_count;
 
-	if (eth_dev->data->dev_started && internals->mode == BONDING_MODE_8023AD)
-		bond_mode_8023ad_start(eth_dev);
+	if (eth_dev->data->dev_started) {
+	   if (internals->mode == BONDING_MODE_8023AD) {
+			   bond_mode_8023ad_start(eth_dev);
+	   } else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {
+			   bond_tlb_enable(internals);
+	   } else if (internals->mode == BONDING_MODE_ALB) {
+			   bond_tlb_enable(internals);
+			   bond_mode_alb_client_list_upd(eth_dev);
+	   }
+	}
 }
 
 uint8_t
diff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c
index ca4de38..a3f7f55 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_args.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c
@@ -175,6 +175,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,
 #endif
 	case BONDING_MODE_8023AD:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 		return 0;
 	default:
 		RTE_BOND_LOG(ERR, "Invalid slave mode value (%s) specified", value);
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index 09b0f30..39039ba 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -56,6 +56,26 @@
 /* Table for statistics in mode 5 TLB */
 static uint64_t tlb_last_obytets[RTE_MAX_ETHPORTS];
 
+static inline size_t
+get_vlan_offset(struct ether_hdr *eth_hdr, uint16_t *proto)
+{
+	size_t vlan_offset = 0;
+
+	if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
+
+		vlan_offset = sizeof(struct vlan_hdr);
+		*proto = vlan_hdr->eth_proto;
+
+		if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+			vlan_hdr = vlan_hdr + 1;
+			*proto = vlan_hdr->eth_proto;
+			vlan_offset += sizeof(struct vlan_hdr);
+		}
+	}
+	return vlan_offset;
+}
+
 static uint16_t
 bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
@@ -173,6 +193,34 @@ bond_ethdev_rx_burst_8023ad(void *queue, struct rte_mbuf **bufs,
 }
 
 static uint16_t
+bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;
+	struct bond_dev_private *internals = bd_tx_q->dev_private;
+
+	struct ether_hdr *eth_h;
+
+	uint16_t ether_type, offset;
+	uint16_t nb_recv_pkts;
+
+	int i;
+
+	nb_recv_pkts = bond_ethdev_rx_burst(queue, bufs, nb_pkts);
+
+	for (i = 0; i < nb_recv_pkts; i++) {
+		eth_h = rte_pktmbuf_mtod(bufs[i], struct ether_hdr *);
+		ether_type = eth_h->ether_type;
+		offset = get_vlan_offset(eth_h, &ether_type);
+
+		if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+			bond_mode_alb_arp_recv(eth_h, offset, internals);
+		}
+	}
+
+	return nb_recv_pkts;
+}
+
+static uint16_t
 bond_ethdev_tx_burst_round_robin(void *queue, struct rte_mbuf **bufs,
 		uint16_t nb_pkts)
 {
@@ -281,26 +329,6 @@ ipv6_hash(struct ipv6_hdr *ipv6_hdr)
 			(word_src_addr[3] ^ word_dst_addr[3]);
 }
 
-static inline size_t
-get_vlan_offset(struct ether_hdr *eth_hdr, uint16_t *proto)
-{
-	size_t vlan_offset = 0;
-
-	if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
-		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
-		vlan_offset = sizeof(struct vlan_hdr);
-		*proto = vlan_hdr->eth_proto;
-
-		if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
-			vlan_hdr = vlan_hdr + 1;
-
-			*proto = vlan_hdr->eth_proto;
-			vlan_offset += sizeof(struct vlan_hdr);
-		}
-	}
-	return vlan_offset;
-}
-
 uint16_t
 xmit_l2_hash(const struct rte_mbuf *buf, uint8_t slave_count)
 {
@@ -396,6 +424,15 @@ struct bwg_slave {
 	uint8_t slave;
 };
 
+void
+bond_tlb_activate_slave(struct bond_dev_private *internals) {
+	int i;
+
+	for (i = 0; i < internals->active_slave_count; i++) {
+		tlb_last_obytets[internals->active_slaves[i]] = 0;
+	}
+}
+
 static int
 bandwidth_cmp(const void *a, const void *b)
 {
@@ -426,7 +463,7 @@ bandwidth_left(int port_id, uint64_t load, uint8_t update_idx,
 	uint64_t link_bwg = link_status.link_speed * 1000000ULL / 8;
 	if (link_bwg == 0)
 		return;
-	link_bwg = (link_bwg * (update_idx+1) * REORDER_PERIOD_MS);
+	link_bwg = link_bwg * (update_idx+1) * REORDER_PERIOD_MS;
 	bwg_slave->bwg_left_int = (link_bwg - 1000*load) / link_bwg;
 	bwg_slave->bwg_left_remainder = (link_bwg - 1000*load) % link_bwg;
 }
@@ -457,8 +494,9 @@ bond_ethdev_update_tlb_slave_cb(void *arg)
 				internals->slave_update_idx, &bwg_array[i]);
 		bwg_array[i].slave = slave_id;
 
-		if (update_stats)
+		if (update_stats) {
 			tlb_last_obytets[slave_id] = slave_stats.obytes;
+		}
 	}
 
 	if (update_stats == 1)
@@ -467,7 +505,7 @@ bond_ethdev_update_tlb_slave_cb(void *arg)
 	slave_count = i;
 	qsort(bwg_array, slave_count, sizeof(bwg_array[0]), bandwidth_cmp);
 	for (i = 0; i < slave_count; i++)
-		internals->active_slaves[i] = bwg_array[i].slave;
+		internals->tlb_slaves_order[i] = bwg_array[i].slave;
 
 	rte_eal_alarm_set(REORDER_PERIOD_MS * 1000, bond_ethdev_update_tlb_slave_cb,
 			(struct bond_dev_private *)internals);
@@ -494,8 +532,8 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	if (num_of_slaves < 1)
 		return num_tx_total;
 
-	memcpy(slaves, internals->active_slaves,
-				sizeof(internals->active_slaves[0]) * num_of_slaves);
+	memcpy(slaves, internals->tlb_slaves_order,
+				sizeof(internals->tlb_slaves_order[0]) * num_of_slaves);
 
 
 	ether_addr_copy(primary_port->data->mac_addrs, &primary_slave_addr);
@@ -506,9 +544,7 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	}
 
 	for (i = 0; i < num_of_slaves; i++) {
-		ether_addr_copy(&internals->slaves[slaves[i]].persisted_mac_addr,
-				&active_slave_addr);
-
+		rte_eth_macaddr_get(slaves[i], &active_slave_addr);
 		for (j = num_tx_total; j < nb_pkts; j++) {
 			if (j + 3 < nb_pkts)
 				rte_prefetch0(rte_pktmbuf_mtod(bufs[j+3], void*));
@@ -528,6 +564,147 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	return num_tx_total;
 }
 
+void
+bond_tlb_disable(struct bond_dev_private *internals)
+{
+	rte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, internals);
+}
+
+void
+bond_tlb_enable(struct bond_dev_private *internals)
+{
+	bond_ethdev_update_tlb_slave_cb(internals);
+}
+
+static uint16_t
+bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;
+	struct bond_dev_private *internals = bd_tx_q->dev_private;
+
+	struct ether_hdr *eth_h;
+	uint16_t ether_type, offset;
+
+	struct client_data *client_info;
+
+	/*
+	 * We create transmit buffers for every slave and one additional to send
+	 * through tlb. In worst case every packet will be send on one port.
+	 */
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS + 1][nb_pkts];
+	uint16_t slave_bufs_pkts[RTE_MAX_ETHPORTS + 1] = { 0 };
+
+	/*
+	 * We create separate transmit buffers for update packets as they wont be
+	 * counted in num_tx_total.
+	 */
+	struct rte_mbuf *update_bufs[RTE_MAX_ETHPORTS][ALB_HASH_TABLE_SIZE];
+	uint16_t update_bufs_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	struct rte_mbuf *upd_pkt;
+	size_t pkt_size;
+
+	uint16_t num_send, num_not_send = 0;
+	uint16_t num_tx_total = 0;
+	uint8_t slave_idx;
+
+	int i, j;
+
+	/* Search tx buffer for ARP packets and forward them to alb */
+	for (i = 0; i < nb_pkts; i++) {
+		eth_h = rte_pktmbuf_mtod(bufs[i], struct ether_hdr *);
+		ether_type = eth_h->ether_type;
+		offset = get_vlan_offset(eth_h, &ether_type);
+
+		if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+			slave_idx = bond_mode_alb_arp_xmit(eth_h, offset, internals);
+
+			/* Change src mac in eth header */
+			rte_eth_macaddr_get(slave_idx, &eth_h->s_addr);
+
+			/* Add packet to slave tx buffer */
+			slave_bufs[slave_idx][slave_bufs_pkts[slave_idx]] = bufs[i];
+			slave_bufs_pkts[slave_idx]++;
+		} else {
+			/* If packet is not ARP, send it with TLB policy */
+			slave_bufs[RTE_MAX_ETHPORTS][slave_bufs_pkts[RTE_MAX_ETHPORTS]] =
+					bufs[i];
+			slave_bufs_pkts[RTE_MAX_ETHPORTS]++;
+		}
+	}
+
+	/* Update connected client ARP tables */
+	if (internals->mode6.ntt) {
+		for (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {
+			client_info = &internals->mode6.client_table[i];
+
+			if (client_info->in_use) {
+				/* Allocate new packet to send ARP update on current slave */
+				upd_pkt = rte_pktmbuf_alloc(internals->mode6.mempool);
+				if (upd_pkt == NULL) {
+					RTE_LOG(ERR, PMD, "Failed to allocate ARP packet from pool\n");
+					continue;
+				}
+				pkt_size = sizeof(struct ether_hdr) + sizeof(struct arp_hdr)
+						+ client_info->vlan_count * sizeof(struct vlan_hdr);
+				upd_pkt->data_len = pkt_size;
+				upd_pkt->pkt_len = pkt_size;
+
+				slave_idx = bond_mode_alb_arp_upd(client_info, upd_pkt,
+						internals);
+
+				/* Add packet to update tx buffer */
+				update_bufs[slave_idx][update_bufs_pkts[slave_idx]] = upd_pkt;
+				update_bufs_pkts[slave_idx]++;
+			}
+		}
+		internals->mode6.ntt = 0;
+	}
+
+	/* Send ARP packets on proper slaves */
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (slave_bufs_pkts[i] > 0) {
+			num_send = rte_eth_tx_burst(i, bd_tx_q->queue_id,
+					slave_bufs[i], slave_bufs_pkts[i]);
+			for (j = 0; j < slave_bufs_pkts[i] - num_send; j++) {
+				bufs[nb_pkts - 1 - num_not_send - j] =
+						slave_bufs[i][nb_pkts - 1 - j];
+			}
+
+			num_tx_total += num_send;
+			num_not_send += slave_bufs_pkts[i] - num_send;
+		}
+	}
+
+	/* Send update packets on proper slaves */
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (update_bufs_pkts[i] > 0) {
+			num_send = rte_eth_tx_burst(i, bd_tx_q->queue_id, update_bufs[i],
+					update_bufs_pkts[i]);
+			for (j = num_send; j < update_bufs_pkts[i]; j++) {
+				rte_pktmbuf_free(update_bufs[i][j]);
+			}
+		}
+	}
+
+	/* Send non-ARP packets using tlb policy */
+	if (slave_bufs_pkts[RTE_MAX_ETHPORTS] > 0) {
+		num_send = bond_ethdev_tx_burst_tlb(queue,
+				slave_bufs[RTE_MAX_ETHPORTS],
+				slave_bufs_pkts[RTE_MAX_ETHPORTS]);
+
+		for (j = 0; j < slave_bufs_pkts[RTE_MAX_ETHPORTS]; j++) {
+			bufs[nb_pkts - 1 - num_not_send - j] =
+					slave_bufs[RTE_MAX_ETHPORTS][nb_pkts - 1 - j];
+		}
+
+		num_tx_total += num_send;
+		num_not_send += slave_bufs_pkts[RTE_MAX_ETHPORTS] - num_send;
+	}
+
+	return num_tx_total;
+}
+
 static uint16_t
 bond_ethdev_tx_burst_balance(void *queue, struct rte_mbuf **bufs,
 		uint16_t nb_pkts)
@@ -856,6 +1033,7 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
 		break;
 	case BONDING_MODE_ACTIVE_BACKUP:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 	default:
 		for (i = 0; i < internals->slave_count; i++) {
 			if (internals->slaves[i].port_id ==
@@ -921,6 +1099,13 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
 		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb;
 		eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup;
 		break;
+	case BONDING_MODE_ALB:
+		if (bond_mode_alb_enable(eth_dev) != 0)
+			return -1;
+
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_alb;
+		eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_alb;
+		break;
 	default:
 		return -1;
 	}
@@ -1136,8 +1321,9 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_start(eth_dev);
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)
-		bond_ethdev_update_tlb_slave_cb(internals);
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+			internals->mode == BONDING_MODE_ALB)
+		bond_tlb_enable(internals);
 
 	return 0;
 }
@@ -1168,8 +1354,11 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)
 		}
 	}
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {
-		rte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, internals);
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+			internals->mode == BONDING_MODE_ALB) {
+		bond_tlb_disable(internals);
+		for (i = 0; i < internals->active_slave_count; i++)
+			tlb_last_obytets[internals->active_slaves[i]] = 0;
 	}
 
 	internals->active_slave_count = 0;
@@ -1366,8 +1555,12 @@ bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 {
 	struct bond_dev_private *internals = dev->data->dev_private;
 	struct rte_eth_stats slave_stats;
+
 	int i;
 
+	/* clear bonded stats before populating from slaves */
+	memset(stats, 0, sizeof(*stats));
+
 	for (i = 0; i < internals->slave_count; i++) {
 		rte_eth_stats_get(internals->slaves[i].port_id, &slave_stats);
 
@@ -1422,6 +1615,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_enable(internals->current_primary_port);
 	}
@@ -1451,6 +1645,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_disable(internals->current_primary_port);
 	}
diff --git a/lib/librte_pmd_bond/rte_eth_bond_private.h b/lib/librte_pmd_bond/rte_eth_bond_private.h
index 3da5a9e..bef1e81 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_private.h
+++ b/lib/librte_pmd_bond/rte_eth_bond_private.h
@@ -39,6 +39,7 @@
 
 #include "rte_eth_bond.h"
 #include "rte_eth_bond_8023ad_private.h"
+#include "rte_eth_bond_alb.h"
 
 #define PMD_BOND_SLAVE_PORT_KVARG			("slave")
 #define PMD_BOND_PRIMARY_SLAVE_KVARG		("primary")
@@ -148,6 +149,8 @@ struct bond_dev_private {
 	/**< Arary of bonded slaves details */
 
 	struct mode8023ad_private mode4;
+	uint8_t tlb_slaves_order[RTE_MAX_ETHPORTS]; /* TLB active slaves send order */
+	struct mode_alb_private mode6;
 
 	uint32_t rx_offload_capa;            /** Rx offload capability */
 	uint32_t tx_offload_capa;            /** Tx offload capability */
@@ -272,4 +275,13 @@ int
 bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,
 		const char *value, void *extra_args);
 
+void
+bond_tlb_disable(struct bond_dev_private *internals);
+
+void
+bond_tlb_enable(struct bond_dev_private *internals);
+
+void
+bond_tlb_activate_slave(struct bond_dev_private *internals);
+
 #endif
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v3 3/6] bond: add debug info for mode 6 link bonding
  2015-02-19 17:26 ` [dpdk-dev] [PATCH v3 " Michal Jastrzebski
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 2/6] bond: add link bonding mode 6 implementation Michal Jastrzebski
@ 2015-02-19 17:26   ` Michal Jastrzebski
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-19 17:26 UTC (permalink / raw)
  To: dev

This patch add some debug information when using link bonding mode 6.
It prints basic information about ARP packets on RX and TX (MAC, ip,
packet number, arp packet type).
If CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB == y.
If CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1 is enabled instead of previous
one, use show command to see IPv4 balancing from clients.

Signed-off-by: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
---
 config/common_linuxapp                 |    3 +-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c |  199 +++++++++++++++++++++++++++++++-
 2 files changed, 198 insertions(+), 4 deletions(-)

diff --git a/config/common_linuxapp b/config/common_linuxapp
index d428f84..7c54edf 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -220,7 +220,8 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=n
 # Compile link bonding PMD library
 #
 CONFIG_RTE_LIBRTE_PMD_BOND=y
-
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
 #
 # Compile software PMD backed by AF_PACKET sockets (Linux only)
 #
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index 39039ba..af2ef8c 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -192,17 +192,186 @@ bond_ethdev_rx_burst_8023ad(void *queue, struct rte_mbuf **bufs,
 	return num_rx_total;
 }
 
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+uint32_t burstnumberRX;
+uint32_t burstnumberTX;
+
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+
+static void
+arp_op_name(uint16_t arp_op, char *buf)
+{
+	switch (arp_op) {
+	case ARP_OP_REQUEST:
+		snprintf(buf, sizeof("ARP Request"), "%s", "ARP Request");
+		return;
+	case ARP_OP_REPLY:
+		snprintf(buf, sizeof("ARP Reply"), "%s", "ARP Reply");
+		return;
+	case ARP_OP_REVREQUEST:
+		snprintf(buf, sizeof("Reverse ARP Request"), "%s",
+				"Reverse ARP Request");
+		return;
+	case ARP_OP_REVREPLY:
+		snprintf(buf, sizeof("Reverse ARP Reply"), "%s",
+				"Reverse ARP Reply");
+		return;
+	case ARP_OP_INVREQUEST:
+		snprintf(buf, sizeof("Peer Identify Request"), "%s",
+				"Peer Identify Request");
+		return;
+	case ARP_OP_INVREPLY:
+		snprintf(buf, sizeof("Peer Identify Reply"), "%s",
+				"Peer Identify Reply");
+		return;
+	default:
+		break;
+	}
+	snprintf(buf, sizeof("Unknown"), "%s", "Unknown");
+	return;
+}
+#endif
+#define MaxIPv4String	16
+static void
+ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf, uint8_t buf_size)
+{
+	uint32_t ipv4_addr;
+
+	ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr);
+	snprintf(buf, buf_size, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF,
+		(ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF,
+		ipv4_addr & 0xFF);
+}
+
+#define MAX_CLIENTS_NUMBER	128
+uint8_t active_clients;
+struct client_stats_t {
+	uint8_t port;
+	uint32_t ipv4_addr;
+	uint32_t ipv4_rx_packets;
+	uint32_t ipv4_tx_packets;
+};
+struct client_stats_t client_stats[MAX_CLIENTS_NUMBER];
+
+static void
+update_client_stats(uint32_t addr, uint8_t port, uint32_t *TXorRXindicator)
+{
+	int i = 0;
+
+	for (; i < MAX_CLIENTS_NUMBER; i++)	{
+		if ((client_stats[i].ipv4_addr == addr) && (client_stats[i].port == port))	{
+			/* Just update RX packets number for this client */
+			if (TXorRXindicator == &burstnumberRX)
+				client_stats[i].ipv4_rx_packets++;
+			else
+				client_stats[i].ipv4_tx_packets++;
+			return;
+		}
+	}
+	/* We have a new client. Insert him to the table, and increment stats */
+	if (TXorRXindicator == &burstnumberRX)
+		client_stats[active_clients].ipv4_rx_packets++;
+	else
+		client_stats[active_clients].ipv4_tx_packets++;
+	client_stats[active_clients].ipv4_addr = addr;
+	client_stats[active_clients].port = port;
+	active_clients++;
+
+}
+
+void print_client_stats(void);
+void print_client_stats(void)
+{
+	int i = 0;
+	char buf[MaxIPv4String];
+
+	for (; i < active_clients; i++)	{
+		ipv4_addr_to_dot(client_stats[i].ipv4_addr, buf, MaxIPv4String);
+		printf("port:%d client:%s RX:%d TX:%d\n", client_stats[i].port,	buf,
+				client_stats[i].ipv4_rx_packets,
+				client_stats[i].ipv4_tx_packets);
+	}
+}
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+#define MODE6_DEBUG(info, src_ip, dst_ip, eth_h, arp_op, port, burstnumber)	\
+		RTE_LOG(DEBUG, PMD, \
+		"%s " \
+		"port:%d " \
+		"SrcMAC:%02X:%02X:%02X:%02X:%02X:%02X " \
+		"SrcIP:%s " \
+		"DstMAC:%02X:%02X:%02X:%02X:%02X:%02X " \
+		"DstIP:%s " \
+		"%s " \
+		"%d\n", \
+		info, \
+		port, \
+		eth_h->s_addr.addr_bytes[0], \
+		eth_h->s_addr.addr_bytes[1], \
+		eth_h->s_addr.addr_bytes[2], \
+		eth_h->s_addr.addr_bytes[3], \
+		eth_h->s_addr.addr_bytes[4], \
+		eth_h->s_addr.addr_bytes[5], \
+		src_ip, \
+		eth_h->d_addr.addr_bytes[0], \
+		eth_h->d_addr.addr_bytes[1], \
+		eth_h->d_addr.addr_bytes[2], \
+		eth_h->d_addr.addr_bytes[3], \
+		eth_h->d_addr.addr_bytes[4], \
+		eth_h->d_addr.addr_bytes[5], \
+		dst_ip, \
+		arp_op, \
+		++burstnumber)
+#endif
+
+static void
+mode6_debug(const char __attribute__((unused)) *info, struct ether_hdr *eth_h,
+		uint8_t port, uint32_t __attribute__((unused)) *burstnumber)
+{
+	struct ipv4_hdr *ipv4_h;
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+	struct arp_hdr *arp_h;
+	char dst_ip[16];
+	char ArpOp[24];
+	char buf[16];
+#endif
+	char src_ip[16];
+
+	uint16_t ether_type = eth_h->ether_type;
+	uint16_t offset = get_vlan_offset(eth_h, &ether_type);
+
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+	snprintf(buf, 16, "%s", info);
+#endif
+
+	if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		ipv4_h = (struct ipv4_hdr *)((char *)(eth_h + 1) + offset);
+		ipv4_addr_to_dot(ipv4_h->src_addr, src_ip, MaxIPv4String);
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+		ipv4_addr_to_dot(ipv4_h->dst_addr, dst_ip, MaxIPv4String);
+		MODE6_DEBUG(buf, src_ip, dst_ip, eth_h, "", port, *burstnumber);
+#endif
+		update_client_stats(ipv4_h->src_addr, port, burstnumber);
+	}
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+	else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+		arp_h = (struct arp_hdr *)((char *)(eth_h + 1) + offset);
+		ipv4_addr_to_dot(arp_h->arp_data.arp_sip, src_ip, MaxIPv4String);
+		ipv4_addr_to_dot(arp_h->arp_data.arp_tip, dst_ip, MaxIPv4String);
+		arp_op_name(rte_be_to_cpu_16(arp_h->arp_op), ArpOp);
+		MODE6_DEBUG(buf, src_ip, dst_ip, eth_h, ArpOp, port, *burstnumber);
+	}
+#endif
+}
+#endif
+
 static uint16_t
 bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
 	struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;
 	struct bond_dev_private *internals = bd_tx_q->dev_private;
-
 	struct ether_hdr *eth_h;
-
 	uint16_t ether_type, offset;
 	uint16_t nb_recv_pkts;
-
 	int i;
 
 	nb_recv_pkts = bond_ethdev_rx_burst(queue, bufs, nb_pkts);
@@ -213,8 +382,15 @@ bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		offset = get_vlan_offset(eth_h, &ether_type);
 
 		if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+		mode6_debug("RX ARP:", eth_h, bufs[i]->port, &burstnumberRX);
+#endif
 			bond_mode_alb_arp_recv(eth_h, offset, internals);
 		}
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+		else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
+			mode6_debug("RX IPv4:", eth_h, bufs[i]->port, &burstnumberRX);
+#endif
 	}
 
 	return nb_recv_pkts;
@@ -552,6 +728,9 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			ether_hdr = rte_pktmbuf_mtod(bufs[j], struct ether_hdr *);
 			if (is_same_ether_addr(&ether_hdr->s_addr, &primary_slave_addr))
 				ether_addr_copy(&active_slave_addr, &ether_hdr->s_addr);
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+					mode6_debug("TX IPv4:", ether_hdr, slaves[i], &burstnumberTX);
+#endif
 		}
 
 		num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
@@ -673,6 +852,14 @@ bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 
 			num_tx_total += num_send;
 			num_not_send += slave_bufs_pkts[i] - num_send;
+
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+	/* Print TX stats including update packets */
+			for (j = 0; j < slave_bufs_pkts[i]; j++) {
+				eth_h = rte_pktmbuf_mtod(slave_bufs[i][j], struct ether_hdr *);
+				mode6_debug("TX ARP:", eth_h, i, &burstnumberTX);
+			}
+#endif
 		}
 	}
 
@@ -684,6 +871,12 @@ bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			for (j = num_send; j < update_bufs_pkts[i]; j++) {
 				rte_pktmbuf_free(update_bufs[i][j]);
 			}
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+			for (j = 0; j < update_bufs_pkts[i]; j++) {
+				eth_h = rte_pktmbuf_mtod(update_bufs[i][j], struct ether_hdr *);
+				mode6_debug("TX ARPupd:", eth_h, i, &burstnumberTX);
+			}
+#endif
 		}
 	}
 
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v3 4/6] bond: add example application for link bonding mode 6
  2015-02-19 17:26 ` [dpdk-dev] [PATCH v3 " Michal Jastrzebski
                     ` (2 preceding siblings ...)
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 3/6] bond: add debug info for mode 6 link bonding Michal Jastrzebski
@ 2015-02-19 17:26   ` Michal Jastrzebski
  2015-02-20 14:42     ` Thomas Monjalon
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 5/6] bond: modify TLB unit tests Michal Jastrzebski
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 6/6] bond: add unit tests for link bonding mode 6 Michal Jastrzebski
  5 siblings, 1 reply; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-19 17:26 UTC (permalink / raw)
  To: dev

This patch contains an example for link bonding mode 6.
It interact with user by a command prompt. Available commands are:
Start - starts ARP_thread which respond to ARP_requests and sends
ARP_updates (this
Is enabled by default after startup),
Stop  -stops ARP_thread,
Send count ip - send count ARP requests for IP,
Show - prints basic bond information, like IPv4 statistics from clients
Help,
Quit.
The best way to test mode 6 is to use this example together with
previous patch:
[PATCH 3/4] bond: add debug info for mode 6 link bonding.
Connect clients thru switch to bonding machine and send:
arping -c 1 bond_ip or
generate IPv4 traffic to bond_ip (IPv4 traffic from different clients
should be then balanced on slaves in round robin manner).

Signed-off-by: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
Signed-off-by: Maciej Gajdzica  <maciejx.t.gajdzica@intel.com>
---
 examples/bond/Makefile |   57 ++++
 examples/bond/main.c   |  796 ++++++++++++++++++++++++++++++++++++++++++++++++
 examples/bond/main.h   |   46 +++
 3 files changed, 899 insertions(+)
 create mode 100644 examples/bond/Makefile
 create mode 100644 examples/bond/main.c
 create mode 100644 examples/bond/main.h

diff --git a/examples/bond/Makefile b/examples/bond/Makefile
new file mode 100644
index 0000000..9262249
--- /dev/null
+++ b/examples/bond/Makefile
@@ -0,0 +1,57 @@
+#   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.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = bond_app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += $(WERROR_FLAGS)
+
+# workaround for a gcc bug with noreturn attribute
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
+CFLAGS_main.o += -Wno-return-type
+endif
+
+CFLAGS += -O3
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/bond/main.c b/examples/bond/main.c
new file mode 100644
index 0000000..e62fbde
--- /dev/null
+++ b/examples/bond/main.c
@@ -0,0 +1,796 @@
+/*-
+ *   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 <stdint.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <termios.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_log.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_memcpy.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_arp.h>
+#include <rte_spinlock.h>
+
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "main.h"
+
+#include <rte_devargs.h>
+
+
+#include "rte_byteorder.h"
+#include "rte_cpuflags.h"
+#include "rte_eth_bond.h"
+
+#define RTE_LOGTYPE_DCB RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   (1024*8)
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100      /* TX drain every ~100us */
+#define BURST_RX_INTERVAL_NS (10) /* RX poll interval ~100ns */
+
+/*
+ * RX and TX Prefetch, Host, and Write-back threshold values should be
+ * carefully set for optimal performance. Consult the network
+ * controller's datasheet and supporting DPDK documentation for guidance
+ * on how these parameters should be set.
+ */
+#define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */
+#define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */
+#define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */
+#define RX_FTHRESH (MAX_PKT_BURST * 2)/**< Default values of RX free threshold reg. */
+
+/*
+ * These default values are optimized for use with the Intel(R) 82599 10 GbE
+ * Controller and the DPDK ixgbe PMD. Consider using other values for other
+ * network controllers and/or network drivers.
+ */
+#define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */
+#define TX_HTHRESH 0  /**< Default values of TX host threshold reg. */
+#define TX_WTHRESH 0  /**< Default values of TX write-back threshold reg. */
+
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_RX_DESC_DEFAULT 128
+#define RTE_TX_DESC_DEFAULT 512
+
+#define BOND_IP_1	7
+#define BOND_IP_2	0
+#define BOND_IP_3	0
+#define BOND_IP_4	10
+
+/* not defined under linux */
+#ifndef NIPQUAD
+#define NIPQUAD_FMT "%u.%u.%u.%u"
+#endif
+
+#define MAX_PORTS	4
+#define PRINT_MAC(addr)		printf("%02"PRIx8":%02"PRIx8":%02"PRIx8 \
+		":%02"PRIx8":%02"PRIx8":%02"PRIx8,	\
+		addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2], \
+		addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5])
+
+uint8_t slaves[RTE_MAX_ETHPORTS];
+uint8_t slaves_count;
+
+static uint8_t BOND_PORT = 0xff;
+
+static struct rte_mempool *mbuf_pool;
+
+static struct rte_eth_conf port_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 */
+	},
+	.rx_adv_conf = {
+		.rss_conf = {
+			.rss_key = NULL,
+			.rss_hf = ETH_RSS_IP,
+		},
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static void
+slave_port_init(uint8_t portid, struct rte_mempool *mbuf_pool)
+{
+	int retval;
+
+	if (portid >= rte_eth_dev_count())
+		rte_exit(EXIT_FAILURE, "Invalid port\n");
+
+	retval = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+	if (retval != 0)
+		rte_exit(EXIT_FAILURE, "port %u: configuration failed (res=%d)\n",
+				portid, retval);
+
+	/* RX setup */
+	retval = rte_eth_rx_queue_setup(portid, 0, RTE_RX_DESC_DEFAULT,
+					rte_eth_dev_socket_id(portid), NULL,
+					mbuf_pool);
+	if (retval < 0)
+		rte_exit(retval, " port %u: RX queue 0 setup failed (res=%d)",
+				portid, retval);
+
+	/* TX setup */
+	retval = rte_eth_tx_queue_setup(portid, 0, RTE_TX_DESC_DEFAULT,
+				rte_eth_dev_socket_id(portid), NULL);
+
+	if (retval < 0)
+		rte_exit(retval, "port %u: TX queue 0 setup failed (res=%d)",
+				portid, retval);
+
+	retval  = rte_eth_dev_start(portid);
+	if (retval < 0)
+		rte_exit(retval,
+				"Start port %d failed (res=%d)",
+				portid, retval);
+
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(portid, &addr);
+	printf("Port %u MAC: ", (unsigned)portid);
+	PRINT_MAC(addr);
+	printf("\n");
+}
+
+static void
+bond_port_init(struct rte_mempool *mbuf_pool)
+{
+	int retval;
+	uint8_t i;
+
+	retval = rte_eth_bond_create("bond0", BONDING_MODE_ALB,
+			0 /*SOCKET_ID_ANY*/);
+	if (retval < 0)
+		rte_exit(EXIT_FAILURE,
+				"Faled to create bond port\n");
+
+	BOND_PORT = (uint8_t)retval;
+
+	retval = rte_eth_dev_configure(BOND_PORT, 1, 1, &port_conf);
+	if (retval != 0)
+		rte_exit(EXIT_FAILURE, "port %u: configuration failed (res=%d)\n",
+				BOND_PORT, retval);
+
+	/* RX setup */
+	retval = rte_eth_rx_queue_setup(BOND_PORT, 0, RTE_RX_DESC_DEFAULT,
+					rte_eth_dev_socket_id(BOND_PORT), NULL,
+					mbuf_pool);
+	if (retval < 0)
+		rte_exit(retval, " port %u: RX queue 0 setup failed (res=%d)",
+				BOND_PORT, retval);
+
+	/* TX setup */
+	retval = rte_eth_tx_queue_setup(BOND_PORT, 0, RTE_TX_DESC_DEFAULT,
+				rte_eth_dev_socket_id(BOND_PORT), NULL);
+
+	if (retval < 0)
+		rte_exit(retval, "port %u: TX queue 0 setup failed (res=%d)",
+				BOND_PORT, retval);
+
+	for (i = 0; i < slaves_count; i++) {
+		if (rte_eth_bond_slave_add(BOND_PORT, slaves[i]) == -1)
+			rte_exit(-1, "Oooops! adding slave (%u) to bond (%u) failed!\n",
+					slaves[i], BOND_PORT);
+
+	}
+
+	retval  = rte_eth_dev_start(BOND_PORT);
+	if (retval < 0)
+		rte_exit(retval, "Start port %d failed (res=%d)", BOND_PORT, retval);
+
+	rte_eth_promiscuous_enable(BOND_PORT);
+
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(BOND_PORT, &addr);
+	printf("Port %u MAC: ", (unsigned)BOND_PORT);
+		PRINT_MAC(addr);
+		printf("\n");
+}
+
+static inline size_t
+get_vlan_offset(struct ether_hdr *eth_hdr, uint16_t *proto)
+{
+	size_t vlan_offset = 0;
+
+	if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
+
+		vlan_offset = sizeof(struct vlan_hdr);
+		*proto = vlan_hdr->eth_proto;
+
+		if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+			vlan_hdr = vlan_hdr + 1;
+
+			*proto = vlan_hdr->eth_proto;
+			vlan_offset += sizeof(struct vlan_hdr);
+		}
+	}
+	return vlan_offset;
+}
+
+struct global_flag_stru_t {
+	int LcoreMainIsRunning;
+	int LcoreMainCore;
+	uint32_t port_packets[4];
+	rte_spinlock_t lock;
+};
+struct global_flag_stru_t global_flag_stru;
+struct global_flag_stru_t *global_flag_stru_p = &global_flag_stru;
+
+/*
+ * Main thread that does the work, reading from INPUT_PORT
+ * and writing to OUTPUT_PORT
+ */
+static int lcore_main(__attribute__((unused)) void *arg1)
+{
+	struct rte_mbuf *pkts[MAX_PKT_BURST] __rte_cache_aligned;
+	struct ether_addr d_addr;
+
+	struct ether_hdr *eth_hdr;
+	struct arp_hdr *arp_hdr;
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t ether_type, offset;
+
+	uint16_t rx_cnt;
+	uint32_t bond_ip;
+	int i = 0;
+	uint8_t is_free;
+
+	bond_ip = BOND_IP_1 | (BOND_IP_2 << 8) |
+				(BOND_IP_3 << 16) | (BOND_IP_4 << 24);
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+
+	while (global_flag_stru_p->LcoreMainIsRunning) {
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		rx_cnt = rte_eth_rx_burst(BOND_PORT, 0, pkts, MAX_PKT_BURST);
+		is_free = 0;
+
+		/* If didn't receive any packets, wait and go to next iteration */
+		if (rx_cnt == 0) {
+			rte_delay_us(50);
+			continue;
+		}
+
+		/* Search incoming data for ARP packets and prepare response */
+		for (i = 0; i < rx_cnt; i++) {
+			if (rte_spinlock_trylock(&global_flag_stru_p->lock) == 1) {
+				global_flag_stru_p->port_packets[0]++;
+				rte_spinlock_unlock(&global_flag_stru_p->lock);
+			}
+			eth_hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+			ether_type = eth_hdr->ether_type;
+			if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_VLAN))
+				printf("VLAN taged frame, offset:");
+			offset = get_vlan_offset(eth_hdr, &ether_type);
+			if (offset > 0)
+				printf("%d\n", offset);
+			if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+				if (rte_spinlock_trylock(&global_flag_stru_p->lock) == 1)     {
+					global_flag_stru_p->port_packets[1]++;
+					rte_spinlock_unlock(&global_flag_stru_p->lock);
+				}
+				arp_hdr = (struct arp_hdr *)((char *)(eth_hdr + 1) + offset);
+				if (arp_hdr->arp_data.arp_tip == bond_ip) {
+					if (arp_hdr->arp_op == rte_cpu_to_be_16(ARP_OP_REQUEST)) {
+						arp_hdr->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
+						/* Switch src and dst data and set bonding MAC */
+						ether_addr_copy(&eth_hdr->s_addr, &eth_hdr->d_addr);
+						rte_eth_macaddr_get(BOND_PORT, &eth_hdr->s_addr);
+						ether_addr_copy(&arp_hdr->arp_data.arp_sha, &arp_hdr->arp_data.arp_tha);
+						arp_hdr->arp_data.arp_tip = arp_hdr->arp_data.arp_sip;
+						rte_eth_macaddr_get(BOND_PORT, &d_addr);
+						ether_addr_copy(&d_addr, &arp_hdr->arp_data.arp_sha);
+						arp_hdr->arp_data.arp_sip = bond_ip;
+						rte_eth_tx_burst(BOND_PORT, 0, &pkts[i], 1);
+						is_free = 1;
+					} else {
+						rte_eth_tx_burst(BOND_PORT, 0, NULL, 0);
+					}
+				}
+			} else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+				if (rte_spinlock_trylock(&global_flag_stru_p->lock) == 1)     {
+					global_flag_stru_p->port_packets[2]++;
+					rte_spinlock_unlock(&global_flag_stru_p->lock);
+				 }
+				ipv4_hdr = (struct ipv4_hdr *)((char *)(eth_hdr + 1) + offset);
+				if (ipv4_hdr->dst_addr == bond_ip) {
+					ether_addr_copy(&eth_hdr->s_addr, &eth_hdr->d_addr);
+					rte_eth_macaddr_get(BOND_PORT, &eth_hdr->s_addr);
+					ipv4_hdr->dst_addr = ipv4_hdr->src_addr;
+					ipv4_hdr->src_addr = bond_ip;
+					rte_eth_tx_burst(BOND_PORT, 0, &pkts[i], 1);
+				}
+
+			}
+
+			/* Free processed packets */
+			if (is_free == 0)
+				rte_pktmbuf_free(pkts[i]);
+		}
+		rte_spinlock_trylock(&global_flag_stru_p->lock);
+	}
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+	printf("BYE lcore_main\n");
+	return 0;
+}
+
+struct cmd_obj_send_result {
+	cmdline_fixed_string_t action;
+	cmdline_ipaddr_t ip;
+};
+static inline void get_string(struct cmd_obj_send_result *res, char *buf, uint8_t size)
+{
+	snprintf(buf, size, NIPQUAD_FMT,
+		((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[0]),
+		((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[1]),
+		((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[2]),
+		((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[3])
+		);
+}
+static void cmd_obj_send_parsed(void *parsed_result,
+		__attribute__((unused)) struct cmdline *cl,
+			       __attribute__((unused)) void *data)
+{
+
+	struct cmd_obj_send_result *res = parsed_result;
+	char ip_str[INET6_ADDRSTRLEN];
+
+	struct rte_mbuf *created_pkt;
+	struct ether_hdr *eth_hdr;
+	struct arp_hdr *arp_hdr;
+
+	uint32_t bond_ip;
+	size_t pkt_size;
+
+	if (res->ip.family == AF_INET)
+		get_string(res, ip_str, INET_ADDRSTRLEN);
+	else
+		cmdline_printf(cl, "Wrong IP format. Only IPv4 is supported\n");
+
+	bond_ip = BOND_IP_1 | (BOND_IP_2 << 8) |
+				(BOND_IP_3 << 16) | (BOND_IP_4 << 24);
+
+	created_pkt = rte_pktmbuf_alloc(mbuf_pool);
+	pkt_size = sizeof(struct ether_hdr) + sizeof(struct arp_hdr);
+	created_pkt->data_len = pkt_size;
+	created_pkt->pkt_len = pkt_size;
+
+	eth_hdr = rte_pktmbuf_mtod(created_pkt, struct ether_hdr *);
+	rte_eth_macaddr_get(BOND_PORT, &eth_hdr->s_addr);
+	memset(&eth_hdr->d_addr, 0xFF, ETHER_ADDR_LEN);
+	eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+
+	arp_hdr = (struct arp_hdr *)((char *)eth_hdr + sizeof(struct ether_hdr));
+	arp_hdr->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
+	arp_hdr->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	arp_hdr->arp_hln = ETHER_ADDR_LEN;
+	arp_hdr->arp_pln = sizeof(uint32_t);
+	arp_hdr->arp_op = rte_cpu_to_be_16(ARP_OP_REQUEST);
+
+	rte_eth_macaddr_get(BOND_PORT, &arp_hdr->arp_data.arp_sha);
+	arp_hdr->arp_data.arp_sip = bond_ip;
+	memset(&arp_hdr->arp_data.arp_tha, 0, ETHER_ADDR_LEN);
+	arp_hdr->arp_data.arp_tip =
+			  ((unsigned char *)&res->ip.addr.ipv4)[0]        |
+			 (((unsigned char *)&res->ip.addr.ipv4)[1] << 8)  |
+			 (((unsigned char *)&res->ip.addr.ipv4)[2] << 16) |
+			 (((unsigned char *)&res->ip.addr.ipv4)[3] << 24);
+	rte_eth_tx_burst(BOND_PORT, 0, &created_pkt, 1);
+
+	rte_delay_ms(100);
+	cmdline_printf(cl, "\n");
+}
+
+cmdline_parse_token_string_t cmd_obj_action_send =
+	TOKEN_STRING_INITIALIZER(struct cmd_obj_send_result, action, "send");
+cmdline_parse_token_ipaddr_t cmd_obj_ip =
+	TOKEN_IPV4_INITIALIZER(struct cmd_obj_send_result, ip);
+
+cmdline_parse_inst_t cmd_obj_send = {
+	.f = cmd_obj_send_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "send client_ip",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_obj_action_send,
+		(void *)&cmd_obj_ip,
+		NULL,
+	},
+};
+
+struct cmd_start_result {
+	cmdline_fixed_string_t start;
+};
+
+static void cmd_start_parsed(__attribute__((unused)) void *parsed_result,
+			       struct cmdline *cl,
+			       __attribute__((unused)) void *data)
+{
+	int slave_core_id = rte_lcore_id();
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	if (global_flag_stru_p->LcoreMainIsRunning == 0)	{
+		if (lcore_config[global_flag_stru_p->LcoreMainCore].state != WAIT)	{
+			rte_spinlock_unlock(&global_flag_stru_p->lock);
+			return;
+		}
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+	} else {
+		cmdline_printf(cl, "lcore_main already running on core:%d\n",
+				global_flag_stru_p->LcoreMainCore);
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		return;
+	}
+
+	/* start lcore main on core != master_core - ARP response thread */
+	slave_core_id = rte_get_next_lcore(rte_lcore_id(), 1, 0);
+	if ((slave_core_id >= RTE_MAX_LCORE) || (slave_core_id == 0))
+		return;
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	global_flag_stru_p->LcoreMainIsRunning = 1;
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+	cmdline_printf(cl,
+			"Starting lcore_main on core %d:%d "
+			"Our IP:%d.%d.%d.%d\n",
+			slave_core_id,
+			rte_eal_remote_launch(lcore_main, NULL, slave_core_id),
+			BOND_IP_1,
+			BOND_IP_2,
+			BOND_IP_3,
+			BOND_IP_4
+		);
+}
+
+cmdline_parse_token_string_t cmd_start_start =
+	TOKEN_STRING_INITIALIZER(struct cmd_start_result, start, "start");
+
+cmdline_parse_inst_t cmd_start = {
+	.f = cmd_start_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "starts listening if not started at startup",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_start_start,
+		NULL,
+	},
+};
+
+struct cmd_help_result {
+	cmdline_fixed_string_t help;
+};
+
+static void cmd_help_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	cmdline_printf(cl,
+			"ALB - link bonding mode 6 example\n"
+			"send IP	- sends one ARPrequest thru bonding for IP.\n"
+			"start		- starts listening ARPs.\n"
+			"stop		- stops lcore_main.\n"
+			"show		- shows some bond info: ex. active slaves etc.\n"
+			"help		- prints help.\n"
+			"quit		- terminate all threads and quit.\n"
+		       );
+}
+
+cmdline_parse_token_string_t cmd_help_help =
+	TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
+
+cmdline_parse_inst_t cmd_help = {
+	.f = cmd_help_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "show help",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_help_help,
+		NULL,
+	},
+};
+
+struct cmd_stop_result {
+	cmdline_fixed_string_t stop;
+};
+
+static void cmd_stop_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	if (global_flag_stru_p->LcoreMainIsRunning == 0)	{
+		cmdline_printf(cl,
+					"lcore_main not running on core:%d\n",
+					global_flag_stru_p->LcoreMainCore);
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		return;
+	}
+	global_flag_stru_p->LcoreMainIsRunning = 0;
+	rte_eal_wait_lcore(global_flag_stru_p->LcoreMainCore);
+	cmdline_printf(cl,
+			"lcore_main stopped on core:%d\n",
+			global_flag_stru_p->LcoreMainCore);
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+}
+
+cmdline_parse_token_string_t cmd_stop_stop =
+	TOKEN_STRING_INITIALIZER(struct cmd_stop_result, stop, "stop");
+
+cmdline_parse_inst_t cmd_stop = {
+	.f = cmd_stop_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "this command do not handle any arguments",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_stop_stop,
+		NULL,
+	},
+};
+
+struct cmd_quit_result {
+	cmdline_fixed_string_t quit;
+};
+
+static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	if (global_flag_stru_p->LcoreMainIsRunning == 0)	{
+		cmdline_printf(cl,
+					"lcore_main not running on core:%d\n",
+					global_flag_stru_p->LcoreMainCore);
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		cmdline_quit(cl);
+		return;
+	}
+	global_flag_stru_p->LcoreMainIsRunning = 0;
+	rte_eal_wait_lcore(global_flag_stru_p->LcoreMainCore);
+	cmdline_printf(cl,
+			"lcore_main stopped on core:%d\n",
+			global_flag_stru_p->LcoreMainCore);
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+	cmdline_quit(cl);
+}
+
+cmdline_parse_token_string_t cmd_quit_quit =
+	TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
+
+cmdline_parse_inst_t cmd_quit = {
+	.f = cmd_quit_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "this command do not handle any arguments",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_quit_quit,
+		NULL,
+	},
+};
+
+extern void print_client_stats(void);
+struct cmd_show_result {
+	cmdline_fixed_string_t show;
+};
+
+static void cmd_show_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	uint8_t slaves[16] = {0};
+	uint8_t len = 16;
+	struct ether_addr addr;
+	uint8_t i = 0;
+
+	while (i < slaves_count)	{
+		rte_eth_macaddr_get(i, &addr);
+		PRINT_MAC(addr);
+		printf("\n");
+		i++;
+	}
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	cmdline_printf(cl,
+			"Active_slaves:%d "
+			"packets received:Tot:%d Arp:%d IPv4:%d\n",
+			rte_eth_bond_active_slaves_get(BOND_PORT, slaves, len),
+			global_flag_stru_p->port_packets[0],
+			global_flag_stru_p->port_packets[1],
+			global_flag_stru_p->port_packets[2]);
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1) || defined(RTE_LIBRTE_BOND_DEBUG_ALB)
+	print_client_stats();
+#endif
+}
+
+cmdline_parse_token_string_t cmd_show_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_result, show, "show");
+
+cmdline_parse_inst_t cmd_show = {
+	.f = cmd_show_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "this command do not handle any arguments",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_show_show,
+		NULL,
+	},
+};
+
+/****** CONTEXT (list of instruction) */
+
+cmdline_parse_ctx_t main_ctx[] = {
+	(cmdline_parse_inst_t *)&cmd_start,
+	(cmdline_parse_inst_t *)&cmd_obj_send,
+	(cmdline_parse_inst_t *)&cmd_stop,
+	(cmdline_parse_inst_t *)&cmd_show,
+	(cmdline_parse_inst_t *)&cmd_quit,
+	(cmdline_parse_inst_t *)&cmd_help,
+	NULL,
+};
+
+/* prompt function, called from main on MASTER lcore */
+static void *prompt(__attribute__((unused)) void *arg1)
+{
+	struct cmdline *cl;
+
+	cl = cmdline_stdin_new(main_ctx, "bond6>");
+	if (cl != NULL) {
+		cmdline_interact(cl);
+		cmdline_stdin_exit(cl);
+	}
+}
+
+/* Main function, does initialisation and calls the per-lcore functions */
+int
+MAIN(int argc, char *argv[])
+{
+	int ret;
+	uint8_t nb_ports, i;
+
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	rte_eal_devargs_dump(stdout);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
+	argc -= ret;
+	argv += ret;
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "Give at least one port\n");
+	else if (nb_ports > MAX_PORTS)
+		rte_exit(EXIT_FAILURE, "You can have max 4 ports\n");
+
+	mbuf_pool = rte_mempool_create("MBUF_POOL", NB_MBUF,
+				       MBUF_SIZE, 32,
+				       sizeof(struct rte_pktmbuf_pool_private),
+				       rte_pktmbuf_pool_init, NULL,
+				       rte_pktmbuf_init, NULL,
+				       rte_socket_id(), 0);
+	if (mbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
+
+	/* initialize all ports */
+	slaves_count = nb_ports;
+	for (i = 0; i < nb_ports; i++) {
+		slave_port_init(i, mbuf_pool);
+		slaves[i] = i;
+	}
+
+	bond_port_init(mbuf_pool);
+
+	rte_spinlock_init(&global_flag_stru_p->lock);
+	int slave_core_id = rte_lcore_id();
+
+	/* check state of lcores */
+	RTE_LCORE_FOREACH_SLAVE(slave_core_id) {
+	if (lcore_config[slave_core_id].state != WAIT)
+		return -EBUSY;
+	}
+	/* start lcore main on core != master_core - ARP response thread */
+	slave_core_id = rte_get_next_lcore(rte_lcore_id(), 1, 0);
+	if ((slave_core_id >= RTE_MAX_LCORE) || (slave_core_id == 0))
+		return -EPERM;
+
+	global_flag_stru_p->LcoreMainIsRunning = 1;
+	global_flag_stru_p->LcoreMainCore = slave_core_id;
+	printf("Starting lcore_main on core %d:%d Our IP:%d.%d.%d.%d\n",
+			slave_core_id,
+			rte_eal_remote_launch((lcore_function_t *)lcore_main,
+					NULL,
+					slave_core_id),
+			BOND_IP_1,
+			BOND_IP_2,
+			BOND_IP_3,
+			BOND_IP_4
+		);
+
+	/* Start prompt for user interact */
+	prompt(NULL);
+
+	rte_delay_ms(100);
+	return 0;
+}
diff --git a/examples/bond/main.h b/examples/bond/main.h
new file mode 100644
index 0000000..2682d15
--- /dev/null
+++ b/examples/bond/main.h
@@ -0,0 +1,46 @@
+/*-
+ *   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 _MAIN_H_
+#define _MAIN_H_
+
+
+#ifdef RTE_EXEC_ENV_BAREMETAL
+#define MAIN _main
+#else
+#define MAIN main
+#endif
+
+int MAIN(int argc, char *argv[]);
+
+#endif /* ifndef _MAIN_H_ */
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v3 5/6] bond: modify TLB unit tests
  2015-02-19 17:26 ` [dpdk-dev] [PATCH v3 " Michal Jastrzebski
                     ` (3 preceding siblings ...)
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
@ 2015-02-19 17:26   ` Michal Jastrzebski
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 6/6] bond: add unit tests for link bonding mode 6 Michal Jastrzebski
  5 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-19 17:26 UTC (permalink / raw)
  To: dev

From: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>

This patch modify mode older name from
BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING to BONDING_MODE_TLB
This patch also changes order of TEST_ASSERT macro in
test_tlb_verify_slave_link_status_change_failover.

Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
---
 app/test/test_link_bonding.c            |   27 ++++++++++++++-------------
 lib/librte_pmd_bond/rte_eth_bond.h      |    2 +-
 lib/librte_pmd_bond/rte_eth_bond_api.c  |    8 ++++----
 lib/librte_pmd_bond/rte_eth_bond_args.c |    2 +-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c  |   12 ++++++------
 5 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index 579ebbf..dd6e357 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -4053,7 +4053,7 @@ test_tlb_tx_burst(void)
 	uint64_t floor_obytes = 0, ceiling_obytes = 0;
 
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves
-			(BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 1, 3, 1),
+			(BONDING_MODE_TLB, 1, 3, 1),
 			"Failed to initialise bonded device");
 
 	burst_size = 20 * test_params->bonded_slave_count;
@@ -4153,7 +4153,7 @@ test_tlb_rx_burst(void)
 
 	/* Initialize bonded device with 4 slaves in transmit load balancing mode */
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING,
+			BONDING_MODE_TLB,
 			TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1, 1),
 			"Failed to initialize bonded device");
 
@@ -4231,7 +4231,7 @@ test_tlb_verify_promiscuous_enable_disable(void)
 
 	/* Initialize bonded device with 4 slaves in transmit load balancing mode */
 	TEST_ASSERT_SUCCESS( initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 4, 1),
+			BONDING_MODE_TLB, 0, 4, 1),
 			"Failed to initialize bonded device");
 
 	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
@@ -4289,7 +4289,7 @@ test_tlb_verify_mac_assignment(void)
 
 	/* Initialize bonded device with 2 slaves in active backup mode */
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 2, 1),
+			BONDING_MODE_TLB, 0, 2, 1),
 			"Failed to initialize bonded device");
 
 	/* Verify that bonded MACs is that of first slave and that the other slave
@@ -4409,7 +4409,7 @@ test_tlb_verify_slave_link_status_change_failover(void)
 
 	/* Initialize bonded device with 4 slaves in round robin mode */
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0,
+			BONDING_MODE_TLB, 0,
 			TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1),
 			"Failed to initialize bonded device with slaves");
 
@@ -4472,20 +4472,21 @@ test_tlb_verify_slave_link_status_change_failover(void)
 		rte_delay_us(11000);
 	}
 
-	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
-	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
-			"(%d) port_stats.opackets not as expected\n",
-			test_params->slave_port_ids[2]);
-
 	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
 	TEST_ASSERT_EQUAL(port_stats.opackets, (int8_t)0,
-			"(%d) port_stats.opackets not as expected\n",
-			test_params->slave_port_ids[0]);
+				"(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
+					"(%d) port_stats.opackets not as expected\n",
+					test_params->slave_port_ids[1]);
+
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
 			"(%d) port_stats.opackets not as expected\n",
-			test_params->slave_port_ids[1]);
+			test_params->slave_port_ids[2]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
diff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h
index 13581cb..4117a70 100644
--- a/lib/librte_pmd_bond/rte_eth_bond.h
+++ b/lib/librte_pmd_bond/rte_eth_bond.h
@@ -96,7 +96,7 @@ extern "C" {
  * to rx_burst should be at least 2 times the slave count size.
  *
  */
-#define BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING	(5)
+#define BONDING_MODE_TLB	(5)
 /**< Adaptive TLB (Mode 5)
  * This mode provides an adaptive transmit load balancing. It dynamically
  * changes the transmitting slave, according to the computed load. Statistics
diff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c
index cbfd185..a5f2c26 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_api.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c
@@ -116,7 +116,7 @@ activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_activate_slave(eth_dev, port_id);
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+	if (internals->mode == BONDING_MODE_TLB
 			|| internals->mode == BONDING_MODE_ALB) {
 
 		internals->tlb_slaves_order[active_count] = port_id;
@@ -128,7 +128,7 @@ activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	internals->active_slaves[internals->active_slave_count] = port_id;
 	internals->active_slave_count++;
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)
+	if (internals->mode == BONDING_MODE_TLB)
 		bond_tlb_activate_slave(internals);
 	if (internals->mode == BONDING_MODE_ALB)
 		bond_mode_alb_client_list_upd(eth_dev);
@@ -144,7 +144,7 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (internals->mode == BONDING_MODE_8023AD) {
 		bond_mode_8023ad_stop(eth_dev);
 		bond_mode_8023ad_deactivate_slave(eth_dev, port_id);
-	} else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+	} else if (internals->mode == BONDING_MODE_TLB
 			|| internals->mode == BONDING_MODE_ALB)
 		bond_tlb_disable(internals);
 
@@ -167,7 +167,7 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (eth_dev->data->dev_started) {
 	   if (internals->mode == BONDING_MODE_8023AD) {
 			   bond_mode_8023ad_start(eth_dev);
-	   } else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {
+	   } else if (internals->mode == BONDING_MODE_TLB) {
 			   bond_tlb_enable(internals);
 	   } else if (internals->mode == BONDING_MODE_ALB) {
 			   bond_tlb_enable(internals);
diff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c
index a3f7f55..0801cb5 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_args.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c
@@ -174,7 +174,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,
 	case BONDING_MODE_BROADCAST:
 #endif
 	case BONDING_MODE_8023AD:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 		return 0;
 	default:
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index af2ef8c..b1040a4 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -1225,7 +1225,7 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
 		bond_mode_8023ad_mac_address_update(bonded_eth_dev);
 		break;
 	case BONDING_MODE_ACTIVE_BACKUP:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 	default:
 		for (i = 0; i < internals->slave_count; i++) {
@@ -1288,7 +1288,7 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
 				"Using mode 4, it is necessary to do TX burst and RX burst "
 				"at least every 100ms.");
 		break;
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb;
 		eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup;
 		break;
@@ -1514,7 +1514,7 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_start(eth_dev);
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+	if (internals->mode == BONDING_MODE_TLB ||
 			internals->mode == BONDING_MODE_ALB)
 		bond_tlb_enable(internals);
 
@@ -1547,7 +1547,7 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)
 		}
 	}
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+	if (internals->mode == BONDING_MODE_TLB ||
 			internals->mode == BONDING_MODE_ALB) {
 		bond_tlb_disable(internals);
 		for (i = 0; i < internals->active_slave_count; i++)
@@ -1807,7 +1807,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
 		break;
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_enable(internals->current_primary_port);
@@ -1837,7 +1837,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
 		break;
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_disable(internals->current_primary_port);
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v3 6/6] bond: add unit tests for link bonding mode 6.
  2015-02-19 17:26 ` [dpdk-dev] [PATCH v3 " Michal Jastrzebski
                     ` (4 preceding siblings ...)
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 5/6] bond: modify TLB unit tests Michal Jastrzebski
@ 2015-02-19 17:26   ` Michal Jastrzebski
  5 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-19 17:26 UTC (permalink / raw)
  To: dev

From: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>

Added 4 unit tests checking link bonding mode 6 behavior.

Also modified virtual_pmd so it is possible to provide packets,
that should be received with rx_burst and to inspect packets
transmitted by tx_burst.

In packet_burst_generator.c function creating eth_header is
modified, so it accepts ether_type as a parameter and function
creating arp_header is added. Updated other unit tests to get
rid of compilation errors.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
---
 app/test/packet_burst_generator.c |   41 +++-
 app/test/packet_burst_generator.h |   11 +-
 app/test/test_link_bonding.c      |  439 +++++++++++++++++++++++++++++++++++--
 app/test/test_pmd_perf.c          |    3 +-
 app/test/virtual_pmd.c            |  109 +++++----
 app/test/virtual_pmd.h            |    5 +-
 6 files changed, 533 insertions(+), 75 deletions(-)

diff --git a/app/test/packet_burst_generator.c b/app/test/packet_burst_generator.c
index e9d059c..b46eed7 100644
--- a/app/test/packet_burst_generator.c
+++ b/app/test/packet_burst_generator.c
@@ -80,11 +80,10 @@ copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
 	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 ipv4, uint8_t vlan_enabled,
-		uint16_t van_id)
+		struct ether_addr *dst_mac, uint16_t ether_type,
+		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);
@@ -95,19 +94,27 @@ initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
 
 		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
 
-		if (ipv4)
-			vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv4);
-		else
-			vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv6);
-
+		vhdr->eth_proto =  rte_cpu_to_be_16(ether_type);
 		vhdr->vlan_tci = van_id;
 	} else {
-		if (ipv4)
-			eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
-		else
-			eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		eth_hdr->ether_type = rte_cpu_to_be_16(ether_type);
 	}
+}
 
+void
+initialize_arp_header(struct arp_hdr *arp_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint32_t src_ip, uint32_t dst_ip,
+		uint32_t opcode)
+{
+	arp_hdr->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
+	arp_hdr->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	arp_hdr->arp_hln = ETHER_ADDR_LEN;
+	arp_hdr->arp_pln = sizeof(uint32_t);
+	arp_hdr->arp_op = rte_cpu_to_be_16(opcode);
+	ether_addr_copy(src_mac, &arp_hdr->arp_data.arp_sha);
+	arp_hdr->arp_data.arp_sip = src_ip;
+	ether_addr_copy(dst_mac, &arp_hdr->arp_data.arp_tha);
+	arp_hdr->arp_data.arp_tip = dst_ip;
 }
 
 uint16_t
@@ -265,9 +272,19 @@ nomore_mbuf:
 		if (ipv4) {
 			pkt->vlan_tci  = ETHER_TYPE_IPv4;
 			pkt->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->vlan_tci  = ETHER_TYPE_IPv6;
 			pkt->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;
diff --git a/app/test/packet_burst_generator.h b/app/test/packet_burst_generator.h
index 666cc8e..edc1044 100644
--- a/app/test/packet_burst_generator.h
+++ b/app/test/packet_burst_generator.h
@@ -40,6 +40,7 @@ extern "C" {
 
 #include <rte_mbuf.h>
 #include <rte_ether.h>
+#include <rte_arp.h>
 #include <rte_ip.h>
 #include <rte_udp.h>
 
@@ -50,11 +51,15 @@ extern "C" {
 #define PACKET_BURST_GEN_PKT_LEN 60
 #define PACKET_BURST_GEN_PKT_LEN_128 128
 
-
 void
 initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
-		struct ether_addr *dst_mac, uint8_t ipv4, uint8_t vlan_enabled,
-		uint16_t van_id);
+		struct ether_addr *dst_mac, uint16_t ether_type,
+		uint8_t vlan_enabled, uint16_t van_id);
+
+void
+initialize_arp_header(struct arp_hdr *arp_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint32_t src_ip, uint32_t dst_ip,
+		uint32_t opcode);
 
 uint16_t
 initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index dd6e357..0a37125 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -1313,17 +1313,22 @@ 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;
+	uint16_t pktlen, generated_burst_size, ether_type;
 	void *ip_hdr;
 
+	if (ipv4)
+		ether_type = ETHER_TYPE_IPv4;
+	else
+		ether_type = ETHER_TYPE_IPv6;
+
 	if (toggle_dst_mac)
 		initialize_eth_header(test_params->pkt_eth_hdr,
 				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
-				ipv4, vlan, vlan_id);
+				ether_type, vlan, vlan_id);
 	else
 		initialize_eth_header(test_params->pkt_eth_hdr,
 				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
-				ipv4, vlan, vlan_id);
+				ether_type, vlan, vlan_id);
 
 
 	if (toggle_udp_port)
@@ -2094,7 +2099,8 @@ test_activebackup_tx_burst(void)
 			"Failed to initialize bonded device with slaves");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+			ETHER_TYPE_IPv4,  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,
@@ -2637,7 +2643,8 @@ test_balance_l2_tx_burst(void)
 			"Failed to set balance xmit policy.");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+			ETHER_TYPE_IPv4, 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,
@@ -2651,7 +2658,8 @@ test_balance_l2_tx_burst(void)
 			"failed to generate packet burst");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
+			ETHER_TYPE_IPv4, 0, 0);
 
 	/* Generate a burst 2 of packets to transmit */
 	TEST_ASSERT_EQUAL(generate_packet_burst(test_params->mbuf_pool, &pkts_burst[1][0],
@@ -3488,7 +3496,8 @@ test_broadcast_tx_burst(void)
 			"Failed to intialise bonded device");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+			ETHER_TYPE_IPv4, 0, 0);
 
 	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
 			dst_port_0, 16);
@@ -4041,6 +4050,23 @@ testsuite_teardown(void)
 	return remove_slaves_and_stop_bonded_device();
 }
 
+static void
+free_virtualpmd_tx_queue(void)
+{
+	int i, slave_port, to_free_cnt;
+	struct rte_mbuf *pkts_to_free[MAX_PKT_BURST];
+
+	/* Free tx queue of virtual pmd */
+	for (slave_port = 0; slave_port < test_params->bonded_slave_count;
+			slave_port++) {
+		to_free_cnt = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_port],
+				pkts_to_free, MAX_PKT_BURST);
+		for (i = 0; i < to_free_cnt; i++)
+			rte_pktmbuf_free(pkts_to_free[i]);
+	}
+}
+
 static int
 test_tlb_tx_burst(void)
 {
@@ -4068,11 +4094,11 @@ test_tlb_tx_burst(void)
 		if (i % 2 == 0) {
 			initialize_eth_header(test_params->pkt_eth_hdr,
 					(struct ether_addr *)src_mac,
-					(struct ether_addr *)dst_mac_0, 1, 0, 0);
+					(struct ether_addr *)dst_mac_0, ETHER_TYPE_IPv4, 0, 0);
 		} else {
 			initialize_eth_header(test_params->pkt_eth_hdr,
 					(struct ether_addr *)test_params->default_slave_mac,
-					(struct ether_addr *)dst_mac_0, 1, 0, 0);
+					(struct ether_addr *)dst_mac_0, ETHER_TYPE_IPv4, 0, 0);
 		}
 		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
 				dst_port_0, 16);
@@ -4086,6 +4112,8 @@ test_tlb_tx_burst(void)
 				burst_size);
 		nb_tx2 += nb_tx;
 
+		free_virtualpmd_tx_queue();
+
 		TEST_ASSERT_EQUAL(nb_tx, burst_size,
 				"number of packet not equal burst size");
 
@@ -4474,14 +4502,13 @@ test_tlb_verify_slave_link_status_change_failover(void)
 
 	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
 	TEST_ASSERT_EQUAL(port_stats.opackets, (int8_t)0,
-				"(%d) port_stats.opackets not as expected\n",
-				test_params->slave_port_ids[0]);
+			"(%d) port_stats.opackets not as expected\n",
+			test_params->slave_port_ids[0]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
-					"(%d) port_stats.opackets not as expected\n",
-					test_params->slave_port_ids[1]);
-
+			"(%d) port_stats.opackets not as expected\n",
+			test_params->slave_port_ids[1]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
@@ -4534,6 +4561,386 @@ test_tlb_verify_slave_link_status_change_failover(void)
 	return remove_slaves_and_stop_bonded_device();
 }
 
+#define TEST_ALB_SLAVE_COUNT	2
+
+static uint8_t mac_client1[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 1};
+static uint8_t mac_client2[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 2};
+static uint8_t mac_client3[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 3};
+static uint8_t mac_client4[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 4};
+
+static uint32_t ip_host = IPV4_ADDR(192, 168, 0, 0);
+static uint32_t ip_client1 = IPV4_ADDR(192, 168, 0, 1);
+static uint32_t ip_client2 = IPV4_ADDR(192, 168, 0, 2);
+static uint32_t ip_client3 = IPV4_ADDR(192, 168, 0, 3);
+static uint32_t ip_client4 = IPV4_ADDR(192, 168, 0, 4);
+
+static int
+test_alb_change_mac_in_reply_sent(void)
+{
+	struct rte_mbuf *pkt;
+	struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+	struct ether_hdr *eth_pkt;
+	struct arp_hdr *arp_pkt;
+
+	int slave_idx, nb_pkts, pkt_idx;
+	int retval = 0;
+
+	struct ether_addr bond_mac, client_mac;
+	struct ether_addr *slave_mac1, *slave_mac2;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	/* Flush tx queue */
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count;
+			slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+	}
+
+	ether_addr_copy(
+			rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+			&bond_mac);
+
+	/*
+	 * Generating four packets with different mac and ip addresses and sending
+	 * them through the bonding port.
+	 */
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client1,
+			ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client2,
+			ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client3,
+			ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client4,
+			ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	slave_mac1 =
+			rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs;
+	slave_mac2 =
+			rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs;
+
+	/*
+	 * Checking if packets are properly distributed on bonding ports. Packets
+	 * 0 and 2 should be sent on port 0 and packets 1 and 3 on port 1.
+	 */
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+
+		for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+			eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+			arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+
+			if (slave_idx%2 == 0) {
+				if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			} else {
+				if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			}
+		}
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
+
+static int
+test_alb_reply_from_client(void)
+{
+	struct ether_hdr *eth_pkt;
+	struct arp_hdr *arp_pkt;
+
+	struct rte_mbuf *pkt;
+	struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+	int slave_idx, nb_pkts, pkt_idx, nb_pkts_sum = 0;
+	int retval = 0;
+
+	struct ether_addr bond_mac, client_mac;
+	struct ether_addr *slave_mac1, *slave_mac2;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	/* Flush tx queue */
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+	}
+
+	ether_addr_copy(
+			rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+			&bond_mac);
+
+	/*
+	 * Generating four packets with different mac and ip addresses and placing
+	 * them in the rx queue to be received by the bonding driver on rx_burst.
+	 */
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client2, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client3, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client4, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	/*
+	 * Issue rx_burst and tx_burst to force bonding driver to send update ARP
+	 * packets to every client in alb table.
+	 */
+	rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+
+	slave_mac1 = rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs;
+	slave_mac2 = rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs;
+
+	/*
+	 * Checking if update ARP packets were properly send on slave ports.
+	 */
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent, MAX_PKT_BURST);
+		nb_pkts_sum += nb_pkts;
+
+		for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+			eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+			arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+
+			if (slave_idx%2 == 0) {
+				if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			} else {
+				if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			}
+		}
+	}
+
+	/* Check if proper number of packets was send */
+	if (nb_pkts_sum < 4) {
+		retval = -1;
+		goto test_end;
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
+
+static int
+test_alb_receive_vlan_reply(void)
+{
+	struct ether_hdr *eth_pkt;
+	struct vlan_hdr *vlan_pkt;
+	struct arp_hdr *arp_pkt;
+
+	struct rte_mbuf *pkt;
+	struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+	int slave_idx, nb_pkts, pkt_idx;
+	int retval = 0;
+
+	struct ether_addr bond_mac, client_mac;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	/* Flush tx queue */
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+	}
+
+	ether_addr_copy(
+			rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+			&bond_mac);
+
+	/*
+	 * Generating packet with double VLAN header and placing it in the rx queue.
+	 */
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_VLAN, 0,
+			0);
+	vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1));
+	vlan_pkt->vlan_tci = rte_cpu_to_be_16(1);
+	vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	vlan_pkt = vlan_pkt+1;
+	vlan_pkt->vlan_tci = rte_cpu_to_be_16(2);
+	vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+	arp_pkt = (struct arp_hdr *)((char *)(vlan_pkt + 1));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+
+	/*
+	 * Checking if VLAN headers in generated ARP Update packet are correct.
+	 */
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+
+		for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+			eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+			vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1));
+			if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(1)) {
+				retval = -1;
+				goto test_end;
+			}
+			if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+				retval = -1;
+				goto test_end;
+			}
+			vlan_pkt = vlan_pkt+1;
+			if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(2)) {
+				retval = -1;
+				goto test_end;
+			}
+			if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+				retval = -1;
+				goto test_end;
+			}
+		}
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
+
+static int
+test_alb_ipv4_tx(void)
+{
+	int burst_size, retval, pkts_send;
+	struct rte_mbuf *pkt_burst[MAX_PKT_BURST];
+
+	retval = 0;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	burst_size = 32;
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0) != burst_size) {
+		retval = -1;
+		goto test_end;
+	}
+
+	/*
+	 * Checking if ipv4 traffic is transmitted via TLB policy.
+	 */
+	pkts_send = rte_eth_tx_burst(
+			test_params->bonded_port_id, 0, pkt_burst, burst_size);
+	if (pkts_send != burst_size) {
+		retval = -1;
+		goto test_end;
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
 
 static struct unit_test_suite link_bonding_test_suite  = {
 	.suite_name = "Link Bonding Unit Test Suite",
@@ -4593,6 +5000,10 @@ static struct unit_test_suite link_bonding_test_suite  = {
 		TEST_CASE(test_tlb_verify_mac_assignment),
 		TEST_CASE(test_tlb_verify_promiscuous_enable_disable),
 		TEST_CASE(test_tlb_verify_slave_link_status_change_failover),
+		TEST_CASE(test_alb_change_mac_in_reply_sent),
+		TEST_CASE(test_alb_reply_from_client),
+		TEST_CASE(test_alb_receive_vlan_reply),
+		TEST_CASE(test_alb_ipv4_tx),
 #ifdef RTE_MBUF_REFCNT
 		TEST_CASE(test_broadcast_tx_burst),
 		TEST_CASE(test_broadcast_tx_burst_slave_tx_fail),
diff --git a/app/test/test_pmd_perf.c b/app/test/test_pmd_perf.c
index bad9503..d6a4a45 100644
--- a/app/test/test_pmd_perf.c
+++ b/app/test/test_pmd_perf.c
@@ -235,8 +235,7 @@ init_traffic(struct rte_mempool *mp,
 
 	initialize_eth_header(&pkt_eth_hdr,
 		(struct ether_addr *)src_mac,
-		(struct ether_addr *)dst_mac, 1, 0, 0);
-	pkt_eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		(struct ether_addr *)dst_mac, ETHER_TYPE_IPv4, 0, 0);
 
 	pktlen = initialize_ipv4_header(&pkt_ipv4_hdr,
 					IPV4_ADDR(10, 0, 0, 1),
diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
index 9fac95d..cd9faf3 100644
--- a/app/test/virtual_pmd.c
+++ b/app/test/virtual_pmd.c
@@ -36,6 +36,7 @@
 #include <rte_malloc.h>
 #include <rte_memcpy.h>
 #include <rte_memory.h>
+#include <rte_ring.h>
 
 #include "virtual_pmd.h"
 
@@ -46,8 +47,8 @@ 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 rte_ring *rx_queue;
+	struct rte_ring *tx_queue;
 
 	int tx_burst_fail_count;
 };
@@ -74,8 +75,16 @@ virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev __rte_unused)
 }
 static void  virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused)
 {
+	struct rte_mbuf *pkt = NULL;
+	struct virtual_ethdev_private *prv = eth_dev->data->dev_private;
+
 	eth_dev->data->dev_link.link_status = 0;
 	eth_dev->data->dev_started = 0;
+	while (rte_ring_dequeue(prv->rx_queue, (void **)&pkt) != -ENOENT)
+		rte_pktmbuf_free(pkt);
+
+	while (rte_ring_dequeue(prv->tx_queue, (void **)&pkt) != -ENOENT)
+		rte_pktmbuf_free(pkt);
 }
 
 static void
@@ -214,8 +223,10 @@ static void
 virtual_ethdev_stats_reset(struct rte_eth_dev *dev)
 {
 	struct virtual_ethdev_private *dev_private = dev->data->dev_private;
+	struct rte_mbuf *pkt = NULL;
 
-	dev_private->rx_pkt_burst_len = 0;
+	while (rte_ring_dequeue(dev_private->tx_queue, (void **)&pkt) == -ENOBUFS)
+			rte_pktmbuf_free(pkt);
 
 	/* Reset internal statistics */
 	memset(&dev_private->eth_stats, 0, sizeof(dev_private->eth_stats));
@@ -318,29 +329,23 @@ virtual_ethdev_rx_burst_success(void *queue __rte_unused,
 	struct virtual_ethdev_queue *pq_map;
 	struct virtual_ethdev_private *dev_private;
 
-	int i;
+	int rx_count, 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) {
+	rx_count = rte_ring_dequeue_burst(dev_private->rx_queue, (void **) bufs,
+			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;
-			}
+	/* increments ipackets count */
+	dev_private->eth_stats.ipackets += rx_count;
 
-			dev_private->eth_stats.ipackets = dev_private->rx_pkt_burst_len;
-		}
-		/* reset private burst values */
-		dev_private->rx_pkt_burst_len = 0;
-	}
+	/* increments ibytes count */
+	for (i = 0; i < rx_count; i++)
+		dev_private->eth_stats.ibytes += rte_pktmbuf_pkt_len(bufs[i]);
 
-	return dev_private->eth_stats.ipackets;
+	return rx_count;
 }
 
 static uint16_t
@@ -359,26 +364,26 @@ virtual_ethdev_tx_burst_success(void *queue, struct rte_mbuf **bufs,
 
 	struct rte_eth_dev *vrtl_eth_dev;
 	struct virtual_ethdev_private *dev_private;
-	uint64_t obytes = 0;
+
 	int i;
 
-	for (i = 0; i < nb_pkts; i++)
-		obytes += rte_pktmbuf_pkt_len(bufs[i]);
 	vrtl_eth_dev = &rte_eth_devices[tx_q->port_id];
 	dev_private = vrtl_eth_dev->data->dev_private;
 
-	if (vrtl_eth_dev->data->dev_link.link_status) {
-		/* increment opacket count */
-		dev_private->eth_stats.opackets += nb_pkts;
-		dev_private->eth_stats.obytes += obytes;
-		/* free packets in burst */
-		for (i = 0; i < nb_pkts; i++)
-			rte_pktmbuf_free(bufs[i]);
+	if (!vrtl_eth_dev->data->dev_link.link_status)
+		nb_pkts = 0;
+	else
+		nb_pkts = rte_ring_enqueue_burst(dev_private->tx_queue, (void **)bufs,
+				nb_pkts);
 
-		return nb_pkts;
-	}
+	/* increment opacket count */
+	dev_private->eth_stats.opackets += nb_pkts;
 
-	return 0;
+	/* increment obytes count */
+	for (i = 0; i < nb_pkts; i++)
+		dev_private->eth_stats.obytes += rte_pktmbuf_pkt_len(bufs[i]);
+
+	return nb_pkts;
 }
 
 static uint16_t
@@ -476,23 +481,28 @@ virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
 	_rte_eth_dev_callback_process(vrtl_eth_dev, RTE_ETH_EVENT_INTR_LSC);
 }
 
-
-
-void
+int
 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];
+	struct virtual_ethdev_private *dev_private =
+			vrtl_eth_dev->data->dev_private;
 
-	int i;
-
-	dev_private = vrtl_eth_dev->data->dev_private;
+	return rte_ring_enqueue_burst(dev_private->rx_queue, (void **)pkt_burst,
+			burst_length);
+}
 
-	for (i = 0; i < burst_length; i++)
-		dev_private->rx_pkt_burst[i] = pkt_burst[i];
+int
+virtual_ethdev_get_mbufs_from_tx_queue(uint8_t port_id,
+		struct rte_mbuf **pkt_burst, int burst_length)
+{
+	struct virtual_ethdev_private *dev_private;
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
 
-	dev_private->rx_pkt_burst_len = burst_length;
+	dev_private = vrtl_eth_dev->data->dev_private;
+	return rte_ring_dequeue_burst(dev_private->tx_queue, (void **)pkt_burst,
+		burst_length);
 }
 
 static uint8_t
@@ -510,7 +520,6 @@ get_number_of_sockets(void)
 	return ++sockets;
 }
 
-
 int
 virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 		uint8_t socket_id, uint8_t isr_support)
@@ -522,6 +531,7 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 	struct eth_dev_ops *dev_ops = NULL;
 	struct rte_pci_id *id_table = NULL;
 	struct virtual_ethdev_private *dev_private = NULL;
+	char name_buf[RTE_RING_NAMESIZE];
 
 
 	/* now do all data allocation - for eth_dev structure, dummy pci driver
@@ -555,6 +565,20 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 	if (dev_private == NULL)
 		goto err;
 
+	memset(dev_private, 0, sizeof(*dev_private));
+
+	snprintf(name_buf, sizeof(name_buf), "%s_rxQ", name);
+	dev_private->rx_queue = rte_ring_create(name_buf, MAX_PKT_BURST, socket_id,
+			0);
+	if (dev_private->rx_queue == NULL)
+		goto err;
+
+	snprintf(name_buf, sizeof(name_buf), "%s_txQ", name);
+	dev_private->tx_queue = rte_ring_create(name_buf, MAX_PKT_BURST, socket_id,
+			0);
+	if (dev_private->tx_queue == NULL)
+		goto err;
+
 	/* reserve an ethdev entry */
 	eth_dev = rte_eth_dev_allocate(name);
 	if (eth_dev == NULL)
@@ -594,7 +618,6 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 	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;
diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h
index 2462853..de00188 100644
--- a/app/test/virtual_pmd.h
+++ b/app/test/virtual_pmd.h
@@ -54,10 +54,13 @@ void
 virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
 		uint8_t link_status);
 
-void
+int
 virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id,
 		struct rte_mbuf **pkts_burst, int burst_length);
 
+int
+virtual_ethdev_get_mbufs_from_tx_queue(uint8_t port_id,
+		struct rte_mbuf **pkt_burst, int burst_length);
 
 /** Control methods for the dev_ops functions pointer to control the behavior
  *  of the Virtual PMD */
-- 
1.7.9.5

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

* Re: [dpdk-dev] [PATCH v3 1/6] net: changed arp_hdr struct declaration
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
@ 2015-02-20 14:30     ` Thomas Monjalon
  2015-02-20 14:54       ` Gajdzica, MaciejX T
  0 siblings, 1 reply; 35+ messages in thread
From: Thomas Monjalon @ 2015-02-20 14:30 UTC (permalink / raw)
  To: Michal Jastrzebski; +Cc: dev

2015-02-19 18:26, Michal Jastrzebski:
> From: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
> 
> Changed MAC address type from uint8_t[6] to struct ether_addr and IP
> address type from uint8_t[4] to uint32_t. Also removed union from
> arp_hdr struct. Updated test-pmd to match new arp_hdr version.
> 
> Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>

Why?
"Changed A to B" is not a sufficient explanation.

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

* Re: [dpdk-dev] [PATCH v3 4/6] bond: add example application for link bonding mode 6
  2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
@ 2015-02-20 14:42     ` Thomas Monjalon
  2015-02-20 16:12       ` Jastrzebski, MichalX K
  0 siblings, 1 reply; 35+ messages in thread
From: Thomas Monjalon @ 2015-02-20 14:42 UTC (permalink / raw)
  To: Michal Jastrzebski; +Cc: dev

2015-02-19 18:26, Michal Jastrzebski:
> + *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.

You should check the date.
Is there some reviews of the copyright at Intel? It's quite common to see
these dates starting and finishing too early.

> +#ifdef RTE_EXEC_ENV_BAREMETAL
> +#define MAIN _main
> +#else
> +#define MAIN main
> +#endif

No more bare metal support.

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

* Re: [dpdk-dev] [PATCH v3 1/6] net: changed arp_hdr struct declaration
  2015-02-20 14:30     ` Thomas Monjalon
@ 2015-02-20 14:54       ` Gajdzica, MaciejX T
  2015-02-20 15:22         ` Thomas Monjalon
  0 siblings, 1 reply; 35+ messages in thread
From: Gajdzica, MaciejX T @ 2015-02-20 14:54 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

> 2015-02-19 18:26, Michal Jastrzebski:
> > From: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
> >
> > Changed MAC address type from uint8_t[6] to struct ether_addr and IP
> > address type from uint8_t[4] to uint32_t. Also removed union from
> > arp_hdr struct. Updated test-pmd to match new arp_hdr version.
> >
> > Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
> 
> Why?
> "Changed A to B" is not a sufficient explanation.

Hi Thomas

I changed commit message to this:

Changed MAC address type from uint8_t[6] to struct ether_addr and IP 
address type from uint8_t[4] to uint32_t to make it consistent with other
DPDK code using MAC and IP addresses. It allows us to use is_same_ether_addr
and ether_addr_copy functions on MAC addresses in ARP header.  Also
removed union from arp_hdr struct to make calls to arp_data items
shorter. Updated test-pmd to match new arp_hdr version.

Is that sufficient?

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

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

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

* Re: [dpdk-dev] [PATCH v3 1/6] net: changed arp_hdr struct declaration
  2015-02-20 14:54       ` Gajdzica, MaciejX T
@ 2015-02-20 15:22         ` Thomas Monjalon
  0 siblings, 0 replies; 35+ messages in thread
From: Thomas Monjalon @ 2015-02-20 15:22 UTC (permalink / raw)
  To: Gajdzica, MaciejX T; +Cc: dev

2015-02-20 14:54, Gajdzica, MaciejX T:
> > 2015-02-19 18:26, Michal Jastrzebski:
> > > From: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
> > >
> > > Changed MAC address type from uint8_t[6] to struct ether_addr and IP
> > > address type from uint8_t[4] to uint32_t. Also removed union from
> > > arp_hdr struct. Updated test-pmd to match new arp_hdr version.
> > >
> > > Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
> > 
> > Why?
> > "Changed A to B" is not a sufficient explanation.
> 
> Hi Thomas
> 
> I changed commit message to this:
> 
> Changed MAC address type from uint8_t[6] to struct ether_addr and IP 
> address type from uint8_t[4] to uint32_t to make it consistent with other
> DPDK code using MAC and IP addresses. It allows us to use is_same_ether_addr
> and ether_addr_copy functions on MAC addresses in ARP header.  Also
> removed union from arp_hdr struct to make calls to arp_data items
> shorter. Updated test-pmd to match new arp_hdr version.
> 
> Is that sufficient?

Yes it's far better! Thanks

One day we could have a script to run before sending a patch.
It would make some smoky tests and ask:
"did you explain why you make this change?" ;)

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

Please try to remove this footer.
This email was distributed by the mailing list engine, despite it's prohibited.
I don't want to go in jailhouse ;)

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

* [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB)
  2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                   ` (7 preceding siblings ...)
  2015-02-19 17:26 ` [dpdk-dev] [PATCH v3 " Michal Jastrzebski
@ 2015-02-20 16:09 ` Michal Jastrzebski
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
                     ` (6 more replies)
  8 siblings, 7 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-20 16:09 UTC (permalink / raw)
  To: dev

v4 changes:
- license year modified
- aded license to rte_eth_bond_alb files
- removed RTE_EXEC_ENV_BAREMETAL in #define

v3 changes:
- completed description for mode 5 unit tests patch
- fixed errors required by checkpatch.pl
- moved patch version changes from patches to cover-letter

v2 changes:
in mode 6 patch 2/6:
- add VLAN support
- fixed sending duplicated ARPupdates
- fixed assigning slaves for next clients
- fixed TLB mode

in debug patch 3/6:
- add IPv4 RX/TX information
- add mode6_debug(..) function

in the example application patch 4/6:
- remove count parameter from send command
- fixed quit command to use cmdline_quit(cl)
- add echo function - all IPv4 packets will be retransmitted. Bonding
	driver will use TLB policy - this will show how TX works in mode 6
- remove unused structures rx_conf_default and tx_conf_default
- add VLAN support
- remove unnecessary comments
- nodify show command in term of printing DEBUG informations

This patchset add support for link bonding mode 6.
Additionally it changes an arp_header structure definition.
Also a basic example is introduced. Using this example,
Bonding will configure each client ARP table,
that packets from each client will be received on different slave,
mode 6 uses round-robin policy to assign slave to client IP address.

Daniel Mrzyglod (1):
  bond: modify TLB unit tests

Maciej Gajdzica (3):
  net: changed arp_hdr struct declaration
  bond: add link bonding mode 6 implementation
  bond: add unit tests for link bonding mode 6.

Michal Jastrzebski (2):
  bond: add debug info for mode 6 link bonding
  bond: add example application for link bonding mode 6

 app/test-pmd/icmpecho.c                    |   27 +-
 app/test/packet_burst_generator.c          |   41 +-
 app/test/packet_burst_generator.h          |   11 +-
 app/test/test_link_bonding.c               |  450 +++++++++++++++-
 app/test/test_pmd_perf.c                   |    3 +-
 app/test/virtual_pmd.c                     |  109 ++--
 app/test/virtual_pmd.h                     |    5 +-
 config/common_linuxapp                     |    3 +-
 examples/bond/Makefile                     |   57 ++
 examples/bond/main.c                       |  796 ++++++++++++++++++++++++++++
 examples/bond/main.h                       |   39 ++
 lib/librte_net/rte_arp.h                   |   13 +-
 lib/librte_pmd_bond/Makefile               |    1 +
 lib/librte_pmd_bond/rte_eth_bond.h         |   11 +-
 lib/librte_pmd_bond/rte_eth_bond_alb.c     |  289 ++++++++++
 lib/librte_pmd_bond/rte_eth_bond_alb.h     |  142 +++++
 lib/librte_pmd_bond/rte_eth_bond_api.c     |   28 +-
 lib/librte_pmd_bond/rte_eth_bond_args.c    |    3 +-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  460 ++++++++++++++--
 lib/librte_pmd_bond/rte_eth_bond_private.h |   12 +
 20 files changed, 2354 insertions(+), 146 deletions(-)
 create mode 100644 examples/bond/Makefile
 create mode 100644 examples/bond/main.c
 create mode 100644 examples/bond/main.h
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h

-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v4 1/6] net: changed arp_hdr struct declaration
  2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
@ 2015-02-20 16:09   ` Michal Jastrzebski
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 2/6] bond: add link bonding mode 6 implementation Michal Jastrzebski
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-20 16:09 UTC (permalink / raw)
  To: dev

From: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>

Changed MAC address type from uint8_t[6] to struct ether_addr and IP
address type from uint8_t[4] to uint32_t to make it consistent with
other DPDK code using MAC and IP addresses. It allows us to use
is_same_ether_addr and ether_addr_copy functions on MAC addresses in ARP header.  Also
removed union from arp_hdr struct to make calls to arp_data items
shorter. Updated test-pmd to match new arp_hdr version.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
---
 app/test-pmd/icmpecho.c  |   27 ++++++++++-----------------
 lib/librte_net/rte_arp.h |   13 ++++++-------
 2 files changed, 16 insertions(+), 24 deletions(-)

diff --git a/app/test-pmd/icmpecho.c b/app/test-pmd/icmpecho.c
index 08ea01d..010c5a9 100644
--- a/app/test-pmd/icmpecho.c
+++ b/app/test-pmd/icmpecho.c
@@ -371,18 +371,14 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 				continue;
 			}
 			if (verbose_level > 0) {
-				memcpy(&eth_addr,
-				       arp_h->arp_data.arp_ip.arp_sha, 6);
+				ether_addr_copy(&arp_h->arp_data.arp_sha, &eth_addr);
 				ether_addr_dump("        sha=", &eth_addr);
-				memcpy(&ip_addr,
-				       arp_h->arp_data.arp_ip.arp_sip, 4);
+				ip_addr = arp_h->arp_data.arp_sip;
 				ipv4_addr_dump(" sip=", ip_addr);
 				printf("\n");
-				memcpy(&eth_addr,
-				       arp_h->arp_data.arp_ip.arp_tha, 6);
+				ether_addr_copy(&arp_h->arp_data.arp_tha, &eth_addr);
 				ether_addr_dump("        tha=", &eth_addr);
-				memcpy(&ip_addr,
-				       arp_h->arp_data.arp_ip.arp_tip, 4);
+				ip_addr = arp_h->arp_data.arp_tip;
 				ipv4_addr_dump(" tip=", ip_addr);
 				printf("\n");
 			}
@@ -402,17 +398,14 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 					&eth_h->s_addr);
 
 			arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
-			memcpy(&eth_addr, arp_h->arp_data.arp_ip.arp_tha, 6);
-			memcpy(arp_h->arp_data.arp_ip.arp_tha,
-			       arp_h->arp_data.arp_ip.arp_sha, 6);
-			memcpy(arp_h->arp_data.arp_ip.arp_sha,
-			       &eth_h->s_addr, 6);
+			ether_addr_copy(&arp_h->arp_data.arp_tha, &eth_addr);
+			ether_addr_copy(&arp_h->arp_data.arp_sha, &arp_h->arp_data.arp_tha);
+			ether_addr_copy(&eth_addr, &arp_h->arp_data.arp_sha);
 
 			/* Swap IP addresses in ARP payload */
-			memcpy(&ip_addr, arp_h->arp_data.arp_ip.arp_sip, 4);
-			memcpy(arp_h->arp_data.arp_ip.arp_sip,
-			       arp_h->arp_data.arp_ip.arp_tip, 4);
-			memcpy(arp_h->arp_data.arp_ip.arp_tip, &ip_addr, 4);
+			ip_addr = arp_h->arp_data.arp_sip;
+			arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
+			arp_h->arp_data.arp_tip = ip_addr;
 			pkts_burst[nb_replies++] = pkt;
 			continue;
 		}
diff --git a/lib/librte_net/rte_arp.h b/lib/librte_net/rte_arp.h
index c7b0e51..72108a1 100644
--- a/lib/librte_net/rte_arp.h
+++ b/lib/librte_net/rte_arp.h
@@ -39,6 +39,7 @@
  */
 
 #include <stdint.h>
+#include <rte_ether.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -48,10 +49,10 @@ extern "C" {
  * ARP header IPv4 payload.
  */
 struct arp_ipv4 {
-	uint8_t  arp_sha[6]; /* sender hardware address */
-	uint8_t  arp_sip[4]; /* sender IP address */
-	uint8_t  arp_tha[6]; /* target hardware address */
-	uint8_t  arp_tip[4]; /* target IP address */
+	struct ether_addr  arp_sha;	/* sender hardware address */
+	uint32_t  arp_sip;			/* sender IP address */
+	struct ether_addr  arp_tha;	/* target hardware address */
+	uint32_t  arp_tip;			/* target IP address */
 } __attribute__((__packed__));
 
 /**
@@ -72,9 +73,7 @@ struct arp_hdr {
 #define	ARP_OP_INVREQUEST 8 /* request to identify peer */
 #define	ARP_OP_INVREPLY   9 /* response identifying peer */
 
-	union {
-		struct arp_ipv4 arp_ip;
-	} arp_data;
+	struct arp_ipv4 arp_data;
 } __attribute__((__packed__));
 
 #ifdef __cplusplus
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v4 2/6] bond: add link bonding mode 6 implementation
  2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
@ 2015-02-20 16:09   ` Michal Jastrzebski
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 3/6] bond: add debug info for mode 6 link bonding Michal Jastrzebski
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-20 16:09 UTC (permalink / raw)
  To: dev

From: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>

This mode includes adaptive TLB and receive load balancing (RLB). In RLB
the bonding driver intercepts ARP replies send by local system and
overwrites its source MAC address, so that different peers send data to
the server on different slave interfaces. When local system sends ARP
request, it saves IP information from it. When ARP reply from that peer
is received, its MAC is stored, one of slave MACs assigned and ARP reply
send to that peer.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
Signed-off-by: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
---
 lib/librte_pmd_bond/Makefile               |    1 +
 lib/librte_pmd_bond/rte_eth_bond.h         |    9 +
 lib/librte_pmd_bond/rte_eth_bond_alb.c     |  289 ++++++++++++++++++++++++++++
 lib/librte_pmd_bond/rte_eth_bond_alb.h     |  142 ++++++++++++++
 lib/librte_pmd_bond/rte_eth_bond_api.c     |   28 ++-
 lib/librte_pmd_bond/rte_eth_bond_args.c    |    1 +
 lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  259 ++++++++++++++++++++++---
 lib/librte_pmd_bond/rte_eth_bond_private.h |   12 ++
 8 files changed, 706 insertions(+), 35 deletions(-)
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c
 create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h

diff --git a/lib/librte_pmd_bond/Makefile b/lib/librte_pmd_bond/Makefile
index d6c81a8..cb16356 100644
--- a/lib/librte_pmd_bond/Makefile
+++ b/lib/librte_pmd_bond/Makefile
@@ -50,6 +50,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_api.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_pmd.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_args.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_8023ad.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += rte_eth_bond_alb.c
 
 ifeq ($(CONFIG_RTE_MBUF_REFCNT),n)
 $(info WARNING: Link Bonding Broadcast mode is disabled because it needs MBUF_REFCNT.)
diff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h
index 7177983..13581cb 100644
--- a/lib/librte_pmd_bond/rte_eth_bond.h
+++ b/lib/librte_pmd_bond/rte_eth_bond.h
@@ -101,6 +101,15 @@ extern "C" {
  * This mode provides an adaptive transmit load balancing. It dynamically
  * changes the transmitting slave, according to the computed load. Statistics
  * are collected in 100ms intervals and scheduled every 10ms */
+#define BONDING_MODE_ALB	(6)
+/**< Adaptive Load Balancing (Mode 6)
+ * This mode includes adaptive TLB and receive load balancing (RLB). In RLB the
+ * bonding driver intercepts ARP replies send by local system and overwrites its
+ * source MAC address, so that different peers send data to the server on
+ * different slave interfaces. When local system sends ARP request, it saves IP
+ * information from it. When ARP reply from that peer is received, its MAC is
+ * stored, one of slave MACs assigned and ARP reply send to that peer.
+ */
 
 /* Balance Mode Transmit Policies */
 #define BALANCE_XMIT_POLICY_LAYER2		(0)
diff --git a/lib/librte_pmd_bond/rte_eth_bond_alb.c b/lib/librte_pmd_bond/rte_eth_bond_alb.c
new file mode 100644
index 0000000..22bde62
--- /dev/null
+++ b/lib/librte_pmd_bond/rte_eth_bond_alb.c
@@ -0,0 +1,289 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 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_eth_bond_private.h"
+#include "rte_eth_bond_alb.h"
+
+static inline uint8_t
+simple_hash(uint8_t *hash_start, int hash_size)
+{
+	int i;
+	uint8_t hash;
+
+	hash = 0;
+	for (i = 0; i < hash_size; ++i)
+		hash ^= hash_start[i];
+
+	return hash;
+}
+
+static uint8_t
+calculate_slave(struct bond_dev_private *internals)
+{
+	uint8_t idx;
+
+	idx = (internals->mode6.last_slave + 1) % internals->active_slave_count;
+	internals->mode6.last_slave = idx;
+	return internals->active_slaves[idx];
+}
+
+int
+bond_mode_alb_enable(struct rte_eth_dev *bond_dev)
+{
+	struct bond_dev_private *internals = bond_dev->data->dev_private;
+	struct client_data *hash_table = internals->mode6.client_table;
+
+	uint16_t element_size;
+	char mem_name[RTE_ETH_NAME_MAX_LEN];
+	int socket_id = bond_dev->pci_dev->numa_node;
+
+	/* Fill hash table with initial values */
+	memset(hash_table, 0, sizeof(struct client_data) * ALB_HASH_TABLE_SIZE);
+	rte_spinlock_init(&internals->mode6.lock);
+	internals->mode6.last_slave = ALB_NULL_INDEX;
+	internals->mode6.ntt = 0;
+
+	/* Initialize memory pool for ARP packets to send */
+	if (internals->mode6.mempool == NULL) {
+		/*
+		 * 256 is size of ETH header, ARP header and nested VLAN headers.
+		 * The value is chosen to be cache aligned.
+		 */
+		element_size = 256 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM;
+		snprintf(mem_name, sizeof(mem_name), "%s_MODE6", bond_dev->data->name);
+		internals->mode6.mempool = rte_mempool_create(mem_name,
+				512 * RTE_MAX_ETHPORTS,
+				element_size,
+				RTE_MEMPOOL_CACHE_MAX_SIZE >= 32 ?
+						32 : RTE_MEMPOOL_CACHE_MAX_SIZE,
+				sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init,
+				NULL, rte_pktmbuf_init, NULL, socket_id, 0);
+
+		if (internals->mode6.mempool == NULL) {
+			RTE_LOG(ERR, PMD, "%s: Failed to initialize ALB mempool.\n",
+					bond_dev->data->name);
+			rte_panic(
+					"Failed to alocate memory pool ('%s')\n"
+					"for bond device '%s'\n",
+					mem_name, bond_dev->data->name);
+		}
+	}
+
+	return 0;
+}
+
+void bond_mode_alb_arp_recv(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals) {
+	struct arp_hdr *arp;
+
+	struct client_data *hash_table = internals->mode6.client_table;
+	struct client_data *client_info;
+
+	uint8_t hash_index;
+
+	arp = (struct arp_hdr *) ((char *) (eth_h + 1) + offset);
+
+	/* ARP Requests are forwarded to the application with no changes */
+	if (arp->arp_op != rte_cpu_to_be_16(ARP_OP_REPLY))
+		return;
+
+	/* From now on, we analyze only ARP Reply packets */
+	hash_index = simple_hash((uint8_t *) &arp->arp_data.arp_sip,
+			sizeof(arp->arp_data.arp_sip));
+	client_info = &hash_table[hash_index];
+
+	/*
+	 * We got reply for ARP Request send by the application. We need to
+	 * update client table when received data differ from what is stored
+	 * in ALB table and issue sending update packet to that slave.
+	 */
+	rte_spinlock_lock(&internals->mode6.lock);
+	if (client_info->in_use == 0 ||
+			client_info->app_ip != arp->arp_data.arp_tip ||
+			client_info->cli_ip != arp->arp_data.arp_sip ||
+			!is_same_ether_addr(&client_info->cli_mac, &arp->arp_data.arp_sha) ||
+			client_info->vlan_count != offset / sizeof(struct vlan_hdr) ||
+			memcmp(client_info->vlan, eth_h + 1, offset) != 0
+	) {
+		client_info->in_use = 1;
+		client_info->app_ip = arp->arp_data.arp_tip;
+		client_info->cli_ip = arp->arp_data.arp_sip;
+		ether_addr_copy(&arp->arp_data.arp_sha, &client_info->cli_mac);
+		client_info->slave_idx = calculate_slave(internals);
+		rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+		ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_tha);
+		memcpy(client_info->vlan, eth_h + 1, offset);
+		client_info->vlan_count = offset / sizeof(struct vlan_hdr);
+	}
+	internals->mode6.ntt = 1;
+	rte_spinlock_unlock(&internals->mode6.lock);
+}
+
+uint8_t
+bond_mode_alb_arp_xmit(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals)
+{
+	struct arp_hdr *arp;
+
+	struct client_data *hash_table = internals->mode6.client_table;
+	struct client_data *client_info;
+
+	uint8_t hash_index;
+
+	struct ether_addr bonding_mac;
+
+	arp = (struct arp_hdr *)((char *)(eth_h + 1) + offset);
+
+	/*
+	 * Traffic with src MAC other than bonding should be sent on
+	 * current primary port.
+	 */
+	rte_eth_macaddr_get(internals->port_id, &bonding_mac);
+	if (!is_same_ether_addr(&bonding_mac, &arp->arp_data.arp_sha)) {
+		rte_eth_macaddr_get(internals->current_primary_port,
+				&arp->arp_data.arp_sha);
+		return internals->current_primary_port;
+	}
+
+	hash_index = simple_hash((uint8_t *)&arp->arp_data.arp_tip,
+			sizeof(uint32_t));
+	client_info = &hash_table[hash_index];
+
+	rte_spinlock_lock(&internals->mode6.lock);
+	if (arp->arp_op == rte_cpu_to_be_16(ARP_OP_REPLY)) {
+		if (client_info->in_use) {
+			if (client_info->app_ip == arp->arp_data.arp_sip &&
+				client_info->cli_ip == arp->arp_data.arp_tip) {
+				/* Entry is already assigned to this client */
+				if (!is_broadcast_ether_addr(&arp->arp_data.arp_tha)) {
+					ether_addr_copy(&arp->arp_data.arp_tha,
+							&client_info->cli_mac);
+				}
+				rte_eth_macaddr_get(client_info->slave_idx,
+						&client_info->app_mac);
+				ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);
+				memcpy(client_info->vlan, eth_h + 1, offset);
+				client_info->vlan_count = offset / sizeof(struct vlan_hdr);
+				rte_spinlock_unlock(&internals->mode6.lock);
+				return client_info->slave_idx;
+			}
+		}
+
+		/* Assign new slave to this client and update src mac in ARP */
+		client_info->in_use = 1;
+		client_info->ntt = 0;
+		client_info->app_ip = arp->arp_data.arp_sip;
+		ether_addr_copy(&arp->arp_data.arp_tha, &client_info->cli_mac);
+		client_info->cli_ip = arp->arp_data.arp_tip;
+		client_info->slave_idx = calculate_slave(internals);
+		rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+		ether_addr_copy(&client_info->app_mac, &arp->arp_data.arp_sha);
+		memcpy(client_info->vlan, eth_h + 1, offset);
+		client_info->vlan_count = offset / sizeof(struct vlan_hdr);
+		rte_spinlock_unlock(&internals->mode6.lock);
+		return client_info->slave_idx;
+	}
+
+	/* If packet is not ARP Reply, send it on current primary port. */
+	rte_spinlock_unlock(&internals->mode6.lock);
+	rte_eth_macaddr_get(internals->current_primary_port,
+			&arp->arp_data.arp_sha);
+	return internals->current_primary_port;
+}
+
+uint8_t
+bond_mode_alb_arp_upd(struct client_data *client_info,
+		struct rte_mbuf *pkt, struct bond_dev_private *internals)
+{
+	struct ether_hdr *eth_h;
+	struct arp_hdr *arp_h;
+	uint8_t slave_idx;
+
+	rte_spinlock_lock(&internals->mode6.lock);
+	eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+
+	ether_addr_copy(&client_info->app_mac, &eth_h->s_addr);
+	ether_addr_copy(&client_info->cli_mac, &eth_h->d_addr);
+	if (client_info->vlan_count > 0)
+		eth_h->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	else
+		eth_h->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+
+	arp_h = (struct arp_hdr *)((char *)eth_h + sizeof(struct ether_hdr)
+			+ client_info->vlan_count * sizeof(struct vlan_hdr));
+
+	memcpy(eth_h + 1, client_info->vlan,
+			client_info->vlan_count * sizeof(struct vlan_hdr));
+
+	ether_addr_copy(&client_info->app_mac, &arp_h->arp_data.arp_sha);
+	arp_h->arp_data.arp_sip = client_info->app_ip;
+	ether_addr_copy(&client_info->cli_mac, &arp_h->arp_data.arp_tha);
+	arp_h->arp_data.arp_tip = client_info->cli_ip;
+
+	arp_h->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
+	arp_h->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	arp_h->arp_hln = ETHER_ADDR_LEN;
+	arp_h->arp_pln = sizeof(uint32_t);
+	arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
+
+	slave_idx = client_info->slave_idx;
+	rte_spinlock_unlock(&internals->mode6.lock);
+
+	return slave_idx;
+}
+
+void
+bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev)
+{
+	struct bond_dev_private *internals = bond_dev->data->dev_private;
+	struct client_data *client_info;
+
+	int i;
+
+	/* If active slave count is 0, it's pointless to refresh alb table */
+	if (internals->active_slave_count <= 0)
+		return;
+
+	rte_spinlock_lock(&internals->mode6.lock);
+	internals->mode6.last_slave = ALB_NULL_INDEX;
+
+	for (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {
+		client_info = &internals->mode6.client_table[i];
+		if (client_info->in_use) {
+			client_info->slave_idx = calculate_slave(internals);
+			rte_eth_macaddr_get(client_info->slave_idx, &client_info->app_mac);
+			internals->mode6.ntt = 1;
+		}
+	}
+	rte_spinlock_unlock(&internals->mode6.lock);
+}
diff --git a/lib/librte_pmd_bond/rte_eth_bond_alb.h b/lib/librte_pmd_bond/rte_eth_bond_alb.h
new file mode 100644
index 0000000..fd7c3ae
--- /dev/null
+++ b/lib/librte_pmd_bond/rte_eth_bond_alb.h
@@ -0,0 +1,142 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RTE_ETH_BOND_ALB_H_
+#define RTE_ETH_BOND_ALB_H_
+
+#include <rte_ether.h>
+#include <rte_arp.h>
+
+#define ALB_HASH_TABLE_SIZE	256
+#define ALB_NULL_INDEX		0xFFFFFFFF
+
+struct client_data {
+	/** ARP data of single client */
+	struct ether_addr app_mac;
+	/**< MAC address of application running DPDK */
+	uint32_t app_ip;
+	/**< IP address of application running DPDK */
+	struct ether_addr cli_mac;
+	/**< Client MAC address */
+	uint32_t cli_ip;
+	/**< Client IP address */
+
+	uint8_t slave_idx;
+	/**< Index of slave on which we connect with that client */
+	uint8_t in_use;
+	/**< Flag indicating if entry in client table is currently used */
+	uint8_t ntt;
+	/**< Flag indicating if we need to send update to this client on next tx */
+
+	struct vlan_hdr vlan[2];
+	/**< Content of vlan headers */
+	uint8_t vlan_count;
+	/**< Number of nested vlan headers */
+};
+
+struct mode_alb_private {
+	struct client_data client_table[ALB_HASH_TABLE_SIZE];
+	/**< Hash table storing ARP data of every client connected */
+	struct rte_mempool *mempool;
+	/**< Mempool for creating ARP update packets */
+	uint8_t ntt;
+	/**< Flag indicating if we need to send update to any client on next tx */
+	uint32_t last_slave;
+	/**< Index of last used slave in client table */
+	rte_spinlock_t lock;
+};
+
+/**
+ * ALB mode initialization.
+ *
+ * @param bond_dev		Pointer to bonding device.
+ *
+ * @return
+ * Error code - 0 on success.
+ */
+int
+bond_mode_alb_enable(struct rte_eth_dev *bond_dev);
+
+/**
+ * Function handles ARP packet reception. If received ARP request, it is
+ * forwarded to application without changes. If it is ARP reply, client table
+ * is updated.
+ *
+ * @param eth_h			ETH header of received packet.
+ * @param offset		Vlan header offset.
+ * @param internals		Bonding data.
+ */
+void
+bond_mode_alb_arp_recv(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals);
+
+/**
+ * Function handles ARP packet transmission. It also decides on which slave
+ * send that packet. If packet is ARP Request, it is send on primary slave.
+ * If it is ARP Reply, it is send on slave stored in client table for that
+ * connection. On Reply function also updates data in client table.
+ *
+ * @param eth_h			ETH header of transmitted packet.
+ * @param offset		Vlan header offset.
+ * @param internals		Bonding data.
+ *
+ * @return
+ * Index of slave on which packet should be sent.
+ */
+uint8_t
+bond_mode_alb_arp_xmit(struct ether_hdr *eth_h, uint16_t offset,
+		struct bond_dev_private *internals);
+
+/**
+ * Function fills packet with ARP data from client_info.
+ *
+ * @param client_info	Data of client to which packet is sent.
+ * @param pkt			Pointer to packet which is sent.
+ * @param internals		Bonding data.
+ *
+ * @return
+ * Index of slawe on which packet should be sent.
+ */
+uint8_t
+bond_mode_alb_arp_upd(struct client_data *client_info,
+		struct rte_mbuf *pkt, struct bond_dev_private *internals);
+
+/**
+ * Function updates slave indexes of active connections.
+ *
+ * @param bond_dev		Pointer to bonded device struct.
+ */
+void
+bond_mode_alb_client_list_upd(struct rte_eth_dev *bond_dev);
+
+#endif /* RTE_ETH_BOND_ALB_H_ */
diff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c
index 4ab3267..cbfd185 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_api.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c
@@ -111,15 +111,27 @@ void
 activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 {
 	struct bond_dev_private *internals = eth_dev->data->dev_private;
+	uint8_t active_count = internals->active_slave_count;
 
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_activate_slave(eth_dev, port_id);
 
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+			|| internals->mode == BONDING_MODE_ALB) {
+
+		internals->tlb_slaves_order[active_count] = port_id;
+	}
+
 	RTE_VERIFY(internals->active_slave_count <
 			(RTE_DIM(internals->active_slaves) - 1));
 
 	internals->active_slaves[internals->active_slave_count] = port_id;
 	internals->active_slave_count++;
+
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)
+		bond_tlb_activate_slave(internals);
+	if (internals->mode == BONDING_MODE_ALB)
+		bond_mode_alb_client_list_upd(eth_dev);
 }
 
 void
@@ -132,7 +144,9 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (internals->mode == BONDING_MODE_8023AD) {
 		bond_mode_8023ad_stop(eth_dev);
 		bond_mode_8023ad_deactivate_slave(eth_dev, port_id);
-	}
+	} else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+			|| internals->mode == BONDING_MODE_ALB)
+		bond_tlb_disable(internals);
 
 	slave_pos = find_slave_by_id(internals->active_slaves, active_count,
 			port_id);
@@ -150,8 +164,16 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	RTE_VERIFY(active_count < RTE_DIM(internals->active_slaves));
 	internals->active_slave_count = active_count;
 
-	if (eth_dev->data->dev_started && internals->mode == BONDING_MODE_8023AD)
-		bond_mode_8023ad_start(eth_dev);
+	if (eth_dev->data->dev_started) {
+	   if (internals->mode == BONDING_MODE_8023AD) {
+			   bond_mode_8023ad_start(eth_dev);
+	   } else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {
+			   bond_tlb_enable(internals);
+	   } else if (internals->mode == BONDING_MODE_ALB) {
+			   bond_tlb_enable(internals);
+			   bond_mode_alb_client_list_upd(eth_dev);
+	   }
+	}
 }
 
 uint8_t
diff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c
index ca4de38..a3f7f55 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_args.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c
@@ -175,6 +175,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,
 #endif
 	case BONDING_MODE_8023AD:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 		return 0;
 	default:
 		RTE_BOND_LOG(ERR, "Invalid slave mode value (%s) specified", value);
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index 09b0f30..39039ba 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -56,6 +56,26 @@
 /* Table for statistics in mode 5 TLB */
 static uint64_t tlb_last_obytets[RTE_MAX_ETHPORTS];
 
+static inline size_t
+get_vlan_offset(struct ether_hdr *eth_hdr, uint16_t *proto)
+{
+	size_t vlan_offset = 0;
+
+	if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
+
+		vlan_offset = sizeof(struct vlan_hdr);
+		*proto = vlan_hdr->eth_proto;
+
+		if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+			vlan_hdr = vlan_hdr + 1;
+			*proto = vlan_hdr->eth_proto;
+			vlan_offset += sizeof(struct vlan_hdr);
+		}
+	}
+	return vlan_offset;
+}
+
 static uint16_t
 bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
@@ -173,6 +193,34 @@ bond_ethdev_rx_burst_8023ad(void *queue, struct rte_mbuf **bufs,
 }
 
 static uint16_t
+bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;
+	struct bond_dev_private *internals = bd_tx_q->dev_private;
+
+	struct ether_hdr *eth_h;
+
+	uint16_t ether_type, offset;
+	uint16_t nb_recv_pkts;
+
+	int i;
+
+	nb_recv_pkts = bond_ethdev_rx_burst(queue, bufs, nb_pkts);
+
+	for (i = 0; i < nb_recv_pkts; i++) {
+		eth_h = rte_pktmbuf_mtod(bufs[i], struct ether_hdr *);
+		ether_type = eth_h->ether_type;
+		offset = get_vlan_offset(eth_h, &ether_type);
+
+		if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+			bond_mode_alb_arp_recv(eth_h, offset, internals);
+		}
+	}
+
+	return nb_recv_pkts;
+}
+
+static uint16_t
 bond_ethdev_tx_burst_round_robin(void *queue, struct rte_mbuf **bufs,
 		uint16_t nb_pkts)
 {
@@ -281,26 +329,6 @@ ipv6_hash(struct ipv6_hdr *ipv6_hdr)
 			(word_src_addr[3] ^ word_dst_addr[3]);
 }
 
-static inline size_t
-get_vlan_offset(struct ether_hdr *eth_hdr, uint16_t *proto)
-{
-	size_t vlan_offset = 0;
-
-	if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
-		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
-		vlan_offset = sizeof(struct vlan_hdr);
-		*proto = vlan_hdr->eth_proto;
-
-		if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
-			vlan_hdr = vlan_hdr + 1;
-
-			*proto = vlan_hdr->eth_proto;
-			vlan_offset += sizeof(struct vlan_hdr);
-		}
-	}
-	return vlan_offset;
-}
-
 uint16_t
 xmit_l2_hash(const struct rte_mbuf *buf, uint8_t slave_count)
 {
@@ -396,6 +424,15 @@ struct bwg_slave {
 	uint8_t slave;
 };
 
+void
+bond_tlb_activate_slave(struct bond_dev_private *internals) {
+	int i;
+
+	for (i = 0; i < internals->active_slave_count; i++) {
+		tlb_last_obytets[internals->active_slaves[i]] = 0;
+	}
+}
+
 static int
 bandwidth_cmp(const void *a, const void *b)
 {
@@ -426,7 +463,7 @@ bandwidth_left(int port_id, uint64_t load, uint8_t update_idx,
 	uint64_t link_bwg = link_status.link_speed * 1000000ULL / 8;
 	if (link_bwg == 0)
 		return;
-	link_bwg = (link_bwg * (update_idx+1) * REORDER_PERIOD_MS);
+	link_bwg = link_bwg * (update_idx+1) * REORDER_PERIOD_MS;
 	bwg_slave->bwg_left_int = (link_bwg - 1000*load) / link_bwg;
 	bwg_slave->bwg_left_remainder = (link_bwg - 1000*load) % link_bwg;
 }
@@ -457,8 +494,9 @@ bond_ethdev_update_tlb_slave_cb(void *arg)
 				internals->slave_update_idx, &bwg_array[i]);
 		bwg_array[i].slave = slave_id;
 
-		if (update_stats)
+		if (update_stats) {
 			tlb_last_obytets[slave_id] = slave_stats.obytes;
+		}
 	}
 
 	if (update_stats == 1)
@@ -467,7 +505,7 @@ bond_ethdev_update_tlb_slave_cb(void *arg)
 	slave_count = i;
 	qsort(bwg_array, slave_count, sizeof(bwg_array[0]), bandwidth_cmp);
 	for (i = 0; i < slave_count; i++)
-		internals->active_slaves[i] = bwg_array[i].slave;
+		internals->tlb_slaves_order[i] = bwg_array[i].slave;
 
 	rte_eal_alarm_set(REORDER_PERIOD_MS * 1000, bond_ethdev_update_tlb_slave_cb,
 			(struct bond_dev_private *)internals);
@@ -494,8 +532,8 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	if (num_of_slaves < 1)
 		return num_tx_total;
 
-	memcpy(slaves, internals->active_slaves,
-				sizeof(internals->active_slaves[0]) * num_of_slaves);
+	memcpy(slaves, internals->tlb_slaves_order,
+				sizeof(internals->tlb_slaves_order[0]) * num_of_slaves);
 
 
 	ether_addr_copy(primary_port->data->mac_addrs, &primary_slave_addr);
@@ -506,9 +544,7 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	}
 
 	for (i = 0; i < num_of_slaves; i++) {
-		ether_addr_copy(&internals->slaves[slaves[i]].persisted_mac_addr,
-				&active_slave_addr);
-
+		rte_eth_macaddr_get(slaves[i], &active_slave_addr);
 		for (j = num_tx_total; j < nb_pkts; j++) {
 			if (j + 3 < nb_pkts)
 				rte_prefetch0(rte_pktmbuf_mtod(bufs[j+3], void*));
@@ -528,6 +564,147 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	return num_tx_total;
 }
 
+void
+bond_tlb_disable(struct bond_dev_private *internals)
+{
+	rte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, internals);
+}
+
+void
+bond_tlb_enable(struct bond_dev_private *internals)
+{
+	bond_ethdev_update_tlb_slave_cb(internals);
+}
+
+static uint16_t
+bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;
+	struct bond_dev_private *internals = bd_tx_q->dev_private;
+
+	struct ether_hdr *eth_h;
+	uint16_t ether_type, offset;
+
+	struct client_data *client_info;
+
+	/*
+	 * We create transmit buffers for every slave and one additional to send
+	 * through tlb. In worst case every packet will be send on one port.
+	 */
+	struct rte_mbuf *slave_bufs[RTE_MAX_ETHPORTS + 1][nb_pkts];
+	uint16_t slave_bufs_pkts[RTE_MAX_ETHPORTS + 1] = { 0 };
+
+	/*
+	 * We create separate transmit buffers for update packets as they wont be
+	 * counted in num_tx_total.
+	 */
+	struct rte_mbuf *update_bufs[RTE_MAX_ETHPORTS][ALB_HASH_TABLE_SIZE];
+	uint16_t update_bufs_pkts[RTE_MAX_ETHPORTS] = { 0 };
+
+	struct rte_mbuf *upd_pkt;
+	size_t pkt_size;
+
+	uint16_t num_send, num_not_send = 0;
+	uint16_t num_tx_total = 0;
+	uint8_t slave_idx;
+
+	int i, j;
+
+	/* Search tx buffer for ARP packets and forward them to alb */
+	for (i = 0; i < nb_pkts; i++) {
+		eth_h = rte_pktmbuf_mtod(bufs[i], struct ether_hdr *);
+		ether_type = eth_h->ether_type;
+		offset = get_vlan_offset(eth_h, &ether_type);
+
+		if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+			slave_idx = bond_mode_alb_arp_xmit(eth_h, offset, internals);
+
+			/* Change src mac in eth header */
+			rte_eth_macaddr_get(slave_idx, &eth_h->s_addr);
+
+			/* Add packet to slave tx buffer */
+			slave_bufs[slave_idx][slave_bufs_pkts[slave_idx]] = bufs[i];
+			slave_bufs_pkts[slave_idx]++;
+		} else {
+			/* If packet is not ARP, send it with TLB policy */
+			slave_bufs[RTE_MAX_ETHPORTS][slave_bufs_pkts[RTE_MAX_ETHPORTS]] =
+					bufs[i];
+			slave_bufs_pkts[RTE_MAX_ETHPORTS]++;
+		}
+	}
+
+	/* Update connected client ARP tables */
+	if (internals->mode6.ntt) {
+		for (i = 0; i < ALB_HASH_TABLE_SIZE; i++) {
+			client_info = &internals->mode6.client_table[i];
+
+			if (client_info->in_use) {
+				/* Allocate new packet to send ARP update on current slave */
+				upd_pkt = rte_pktmbuf_alloc(internals->mode6.mempool);
+				if (upd_pkt == NULL) {
+					RTE_LOG(ERR, PMD, "Failed to allocate ARP packet from pool\n");
+					continue;
+				}
+				pkt_size = sizeof(struct ether_hdr) + sizeof(struct arp_hdr)
+						+ client_info->vlan_count * sizeof(struct vlan_hdr);
+				upd_pkt->data_len = pkt_size;
+				upd_pkt->pkt_len = pkt_size;
+
+				slave_idx = bond_mode_alb_arp_upd(client_info, upd_pkt,
+						internals);
+
+				/* Add packet to update tx buffer */
+				update_bufs[slave_idx][update_bufs_pkts[slave_idx]] = upd_pkt;
+				update_bufs_pkts[slave_idx]++;
+			}
+		}
+		internals->mode6.ntt = 0;
+	}
+
+	/* Send ARP packets on proper slaves */
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (slave_bufs_pkts[i] > 0) {
+			num_send = rte_eth_tx_burst(i, bd_tx_q->queue_id,
+					slave_bufs[i], slave_bufs_pkts[i]);
+			for (j = 0; j < slave_bufs_pkts[i] - num_send; j++) {
+				bufs[nb_pkts - 1 - num_not_send - j] =
+						slave_bufs[i][nb_pkts - 1 - j];
+			}
+
+			num_tx_total += num_send;
+			num_not_send += slave_bufs_pkts[i] - num_send;
+		}
+	}
+
+	/* Send update packets on proper slaves */
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (update_bufs_pkts[i] > 0) {
+			num_send = rte_eth_tx_burst(i, bd_tx_q->queue_id, update_bufs[i],
+					update_bufs_pkts[i]);
+			for (j = num_send; j < update_bufs_pkts[i]; j++) {
+				rte_pktmbuf_free(update_bufs[i][j]);
+			}
+		}
+	}
+
+	/* Send non-ARP packets using tlb policy */
+	if (slave_bufs_pkts[RTE_MAX_ETHPORTS] > 0) {
+		num_send = bond_ethdev_tx_burst_tlb(queue,
+				slave_bufs[RTE_MAX_ETHPORTS],
+				slave_bufs_pkts[RTE_MAX_ETHPORTS]);
+
+		for (j = 0; j < slave_bufs_pkts[RTE_MAX_ETHPORTS]; j++) {
+			bufs[nb_pkts - 1 - num_not_send - j] =
+					slave_bufs[RTE_MAX_ETHPORTS][nb_pkts - 1 - j];
+		}
+
+		num_tx_total += num_send;
+		num_not_send += slave_bufs_pkts[RTE_MAX_ETHPORTS] - num_send;
+	}
+
+	return num_tx_total;
+}
+
 static uint16_t
 bond_ethdev_tx_burst_balance(void *queue, struct rte_mbuf **bufs,
 		uint16_t nb_pkts)
@@ -856,6 +1033,7 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
 		break;
 	case BONDING_MODE_ACTIVE_BACKUP:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 	default:
 		for (i = 0; i < internals->slave_count; i++) {
 			if (internals->slaves[i].port_id ==
@@ -921,6 +1099,13 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
 		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb;
 		eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup;
 		break;
+	case BONDING_MODE_ALB:
+		if (bond_mode_alb_enable(eth_dev) != 0)
+			return -1;
+
+		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_alb;
+		eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_alb;
+		break;
 	default:
 		return -1;
 	}
@@ -1136,8 +1321,9 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_start(eth_dev);
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)
-		bond_ethdev_update_tlb_slave_cb(internals);
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+			internals->mode == BONDING_MODE_ALB)
+		bond_tlb_enable(internals);
 
 	return 0;
 }
@@ -1168,8 +1354,11 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)
 		}
 	}
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {
-		rte_eal_alarm_cancel(bond_ethdev_update_tlb_slave_cb, internals);
+	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+			internals->mode == BONDING_MODE_ALB) {
+		bond_tlb_disable(internals);
+		for (i = 0; i < internals->active_slave_count; i++)
+			tlb_last_obytets[internals->active_slaves[i]] = 0;
 	}
 
 	internals->active_slave_count = 0;
@@ -1366,8 +1555,12 @@ bond_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 {
 	struct bond_dev_private *internals = dev->data->dev_private;
 	struct rte_eth_stats slave_stats;
+
 	int i;
 
+	/* clear bonded stats before populating from slaves */
+	memset(stats, 0, sizeof(*stats));
+
 	for (i = 0; i < internals->slave_count; i++) {
 		rte_eth_stats_get(internals->slaves[i].port_id, &slave_stats);
 
@@ -1422,6 +1615,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_enable(internals->current_primary_port);
 	}
@@ -1451,6 +1645,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
 	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_disable(internals->current_primary_port);
 	}
diff --git a/lib/librte_pmd_bond/rte_eth_bond_private.h b/lib/librte_pmd_bond/rte_eth_bond_private.h
index 3da5a9e..bef1e81 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_private.h
+++ b/lib/librte_pmd_bond/rte_eth_bond_private.h
@@ -39,6 +39,7 @@
 
 #include "rte_eth_bond.h"
 #include "rte_eth_bond_8023ad_private.h"
+#include "rte_eth_bond_alb.h"
 
 #define PMD_BOND_SLAVE_PORT_KVARG			("slave")
 #define PMD_BOND_PRIMARY_SLAVE_KVARG		("primary")
@@ -148,6 +149,8 @@ struct bond_dev_private {
 	/**< Arary of bonded slaves details */
 
 	struct mode8023ad_private mode4;
+	uint8_t tlb_slaves_order[RTE_MAX_ETHPORTS]; /* TLB active slaves send order */
+	struct mode_alb_private mode6;
 
 	uint32_t rx_offload_capa;            /** Rx offload capability */
 	uint32_t tx_offload_capa;            /** Tx offload capability */
@@ -272,4 +275,13 @@ int
 bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,
 		const char *value, void *extra_args);
 
+void
+bond_tlb_disable(struct bond_dev_private *internals);
+
+void
+bond_tlb_enable(struct bond_dev_private *internals);
+
+void
+bond_tlb_activate_slave(struct bond_dev_private *internals);
+
 #endif
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v4 3/6] bond: add debug info for mode 6 link bonding
  2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 2/6] bond: add link bonding mode 6 implementation Michal Jastrzebski
@ 2015-02-20 16:09   ` Michal Jastrzebski
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-20 16:09 UTC (permalink / raw)
  To: dev

This patch add some debug information when using link bonding mode 6.
It prints basic information about ARP packets on RX and TX (MAC, ip,
packet number, arp packet type).
If CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB == y.
If CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1 is enabled instead of previous
one, use show command to see IPv4 balancing from clients.

Signed-off-by: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
---
 config/common_linuxapp                 |    3 +-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c |  199 +++++++++++++++++++++++++++++++-
 2 files changed, 198 insertions(+), 4 deletions(-)

diff --git a/config/common_linuxapp b/config/common_linuxapp
index d428f84..7c54edf 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -220,7 +220,8 @@ CONFIG_RTE_LIBRTE_PMD_PCAP=n
 # Compile link bonding PMD library
 #
 CONFIG_RTE_LIBRTE_PMD_BOND=y
-
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n
+CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
 #
 # Compile software PMD backed by AF_PACKET sockets (Linux only)
 #
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index 39039ba..af2ef8c 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -192,17 +192,186 @@ bond_ethdev_rx_burst_8023ad(void *queue, struct rte_mbuf **bufs,
 	return num_rx_total;
 }
 
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+uint32_t burstnumberRX;
+uint32_t burstnumberTX;
+
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+
+static void
+arp_op_name(uint16_t arp_op, char *buf)
+{
+	switch (arp_op) {
+	case ARP_OP_REQUEST:
+		snprintf(buf, sizeof("ARP Request"), "%s", "ARP Request");
+		return;
+	case ARP_OP_REPLY:
+		snprintf(buf, sizeof("ARP Reply"), "%s", "ARP Reply");
+		return;
+	case ARP_OP_REVREQUEST:
+		snprintf(buf, sizeof("Reverse ARP Request"), "%s",
+				"Reverse ARP Request");
+		return;
+	case ARP_OP_REVREPLY:
+		snprintf(buf, sizeof("Reverse ARP Reply"), "%s",
+				"Reverse ARP Reply");
+		return;
+	case ARP_OP_INVREQUEST:
+		snprintf(buf, sizeof("Peer Identify Request"), "%s",
+				"Peer Identify Request");
+		return;
+	case ARP_OP_INVREPLY:
+		snprintf(buf, sizeof("Peer Identify Reply"), "%s",
+				"Peer Identify Reply");
+		return;
+	default:
+		break;
+	}
+	snprintf(buf, sizeof("Unknown"), "%s", "Unknown");
+	return;
+}
+#endif
+#define MaxIPv4String	16
+static void
+ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf, uint8_t buf_size)
+{
+	uint32_t ipv4_addr;
+
+	ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr);
+	snprintf(buf, buf_size, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF,
+		(ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF,
+		ipv4_addr & 0xFF);
+}
+
+#define MAX_CLIENTS_NUMBER	128
+uint8_t active_clients;
+struct client_stats_t {
+	uint8_t port;
+	uint32_t ipv4_addr;
+	uint32_t ipv4_rx_packets;
+	uint32_t ipv4_tx_packets;
+};
+struct client_stats_t client_stats[MAX_CLIENTS_NUMBER];
+
+static void
+update_client_stats(uint32_t addr, uint8_t port, uint32_t *TXorRXindicator)
+{
+	int i = 0;
+
+	for (; i < MAX_CLIENTS_NUMBER; i++)	{
+		if ((client_stats[i].ipv4_addr == addr) && (client_stats[i].port == port))	{
+			/* Just update RX packets number for this client */
+			if (TXorRXindicator == &burstnumberRX)
+				client_stats[i].ipv4_rx_packets++;
+			else
+				client_stats[i].ipv4_tx_packets++;
+			return;
+		}
+	}
+	/* We have a new client. Insert him to the table, and increment stats */
+	if (TXorRXindicator == &burstnumberRX)
+		client_stats[active_clients].ipv4_rx_packets++;
+	else
+		client_stats[active_clients].ipv4_tx_packets++;
+	client_stats[active_clients].ipv4_addr = addr;
+	client_stats[active_clients].port = port;
+	active_clients++;
+
+}
+
+void print_client_stats(void);
+void print_client_stats(void)
+{
+	int i = 0;
+	char buf[MaxIPv4String];
+
+	for (; i < active_clients; i++)	{
+		ipv4_addr_to_dot(client_stats[i].ipv4_addr, buf, MaxIPv4String);
+		printf("port:%d client:%s RX:%d TX:%d\n", client_stats[i].port,	buf,
+				client_stats[i].ipv4_rx_packets,
+				client_stats[i].ipv4_tx_packets);
+	}
+}
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+#define MODE6_DEBUG(info, src_ip, dst_ip, eth_h, arp_op, port, burstnumber)	\
+		RTE_LOG(DEBUG, PMD, \
+		"%s " \
+		"port:%d " \
+		"SrcMAC:%02X:%02X:%02X:%02X:%02X:%02X " \
+		"SrcIP:%s " \
+		"DstMAC:%02X:%02X:%02X:%02X:%02X:%02X " \
+		"DstIP:%s " \
+		"%s " \
+		"%d\n", \
+		info, \
+		port, \
+		eth_h->s_addr.addr_bytes[0], \
+		eth_h->s_addr.addr_bytes[1], \
+		eth_h->s_addr.addr_bytes[2], \
+		eth_h->s_addr.addr_bytes[3], \
+		eth_h->s_addr.addr_bytes[4], \
+		eth_h->s_addr.addr_bytes[5], \
+		src_ip, \
+		eth_h->d_addr.addr_bytes[0], \
+		eth_h->d_addr.addr_bytes[1], \
+		eth_h->d_addr.addr_bytes[2], \
+		eth_h->d_addr.addr_bytes[3], \
+		eth_h->d_addr.addr_bytes[4], \
+		eth_h->d_addr.addr_bytes[5], \
+		dst_ip, \
+		arp_op, \
+		++burstnumber)
+#endif
+
+static void
+mode6_debug(const char __attribute__((unused)) *info, struct ether_hdr *eth_h,
+		uint8_t port, uint32_t __attribute__((unused)) *burstnumber)
+{
+	struct ipv4_hdr *ipv4_h;
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+	struct arp_hdr *arp_h;
+	char dst_ip[16];
+	char ArpOp[24];
+	char buf[16];
+#endif
+	char src_ip[16];
+
+	uint16_t ether_type = eth_h->ether_type;
+	uint16_t offset = get_vlan_offset(eth_h, &ether_type);
+
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+	snprintf(buf, 16, "%s", info);
+#endif
+
+	if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		ipv4_h = (struct ipv4_hdr *)((char *)(eth_h + 1) + offset);
+		ipv4_addr_to_dot(ipv4_h->src_addr, src_ip, MaxIPv4String);
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+		ipv4_addr_to_dot(ipv4_h->dst_addr, dst_ip, MaxIPv4String);
+		MODE6_DEBUG(buf, src_ip, dst_ip, eth_h, "", port, *burstnumber);
+#endif
+		update_client_stats(ipv4_h->src_addr, port, burstnumber);
+	}
+#ifdef RTE_LIBRTE_BOND_DEBUG_ALB
+	else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+		arp_h = (struct arp_hdr *)((char *)(eth_h + 1) + offset);
+		ipv4_addr_to_dot(arp_h->arp_data.arp_sip, src_ip, MaxIPv4String);
+		ipv4_addr_to_dot(arp_h->arp_data.arp_tip, dst_ip, MaxIPv4String);
+		arp_op_name(rte_be_to_cpu_16(arp_h->arp_op), ArpOp);
+		MODE6_DEBUG(buf, src_ip, dst_ip, eth_h, ArpOp, port, *burstnumber);
+	}
+#endif
+}
+#endif
+
 static uint16_t
 bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
 	struct bond_tx_queue *bd_tx_q = (struct bond_tx_queue *)queue;
 	struct bond_dev_private *internals = bd_tx_q->dev_private;
-
 	struct ether_hdr *eth_h;
-
 	uint16_t ether_type, offset;
 	uint16_t nb_recv_pkts;
-
 	int i;
 
 	nb_recv_pkts = bond_ethdev_rx_burst(queue, bufs, nb_pkts);
@@ -213,8 +382,15 @@ bond_ethdev_rx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		offset = get_vlan_offset(eth_h, &ether_type);
 
 		if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+		mode6_debug("RX ARP:", eth_h, bufs[i]->port, &burstnumberRX);
+#endif
 			bond_mode_alb_arp_recv(eth_h, offset, internals);
 		}
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+		else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
+			mode6_debug("RX IPv4:", eth_h, bufs[i]->port, &burstnumberRX);
+#endif
 	}
 
 	return nb_recv_pkts;
@@ -552,6 +728,9 @@ bond_ethdev_tx_burst_tlb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			ether_hdr = rte_pktmbuf_mtod(bufs[j], struct ether_hdr *);
 			if (is_same_ether_addr(&ether_hdr->s_addr, &primary_slave_addr))
 				ether_addr_copy(&active_slave_addr, &ether_hdr->s_addr);
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+					mode6_debug("TX IPv4:", ether_hdr, slaves[i], &burstnumberTX);
+#endif
 		}
 
 		num_tx_total += rte_eth_tx_burst(slaves[i], bd_tx_q->queue_id,
@@ -673,6 +852,14 @@ bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 
 			num_tx_total += num_send;
 			num_not_send += slave_bufs_pkts[i] - num_send;
+
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+	/* Print TX stats including update packets */
+			for (j = 0; j < slave_bufs_pkts[i]; j++) {
+				eth_h = rte_pktmbuf_mtod(slave_bufs[i][j], struct ether_hdr *);
+				mode6_debug("TX ARP:", eth_h, i, &burstnumberTX);
+			}
+#endif
 		}
 	}
 
@@ -684,6 +871,12 @@ bond_ethdev_tx_burst_alb(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			for (j = num_send; j < update_bufs_pkts[i]; j++) {
 				rte_pktmbuf_free(update_bufs[i][j]);
 			}
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB) || defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1)
+			for (j = 0; j < update_bufs_pkts[i]; j++) {
+				eth_h = rte_pktmbuf_mtod(update_bufs[i][j], struct ether_hdr *);
+				mode6_debug("TX ARPupd:", eth_h, i, &burstnumberTX);
+			}
+#endif
 		}
 	}
 
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v4 4/6] bond: add example application for link bonding mode 6
  2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                     ` (2 preceding siblings ...)
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 3/6] bond: add debug info for mode 6 link bonding Michal Jastrzebski
@ 2015-02-20 16:09   ` Michal Jastrzebski
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 5/6] bond: modify TLB unit tests Michal Jastrzebski
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-20 16:09 UTC (permalink / raw)
  To: dev

This patch contains an example for link bonding mode 6.
It interact with user by a command prompt. Available commands are:
Start - starts ARP_thread which respond to ARP_requests and sends
ARP_updates (this
Is enabled by default after startup),
Stop  -stops ARP_thread,
Send count ip - send count ARP requests for IP,
Show - prints basic bond information, like IPv4 statistics from clients
Help,
Quit.
The best way to test mode 6 is to use this example together with
previous patch:
[PATCH 3/4] bond: add debug info for mode 6 link bonding.
Connect clients thru switch to bonding machine and send:
arping -c 1 bond_ip or
generate IPv4 traffic to bond_ip (IPv4 traffic from different clients
should be then balanced on slaves in round robin manner).

Signed-off-by: Michal Jastrzebski <michalx.k.jastrzebski@intel.com>
Signed-off-by: Maciej Gajdzica  <maciejx.t.gajdzica@intel.com>
---
 examples/bond/Makefile |   57 ++++
 examples/bond/main.c   |  796 ++++++++++++++++++++++++++++++++++++++++++++++++
 examples/bond/main.h   |   39 +++
 3 files changed, 892 insertions(+)
 create mode 100644 examples/bond/Makefile
 create mode 100644 examples/bond/main.c
 create mode 100644 examples/bond/main.h

diff --git a/examples/bond/Makefile b/examples/bond/Makefile
new file mode 100644
index 0000000..566cdfa
--- /dev/null
+++ b/examples/bond/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2015 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.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = bond_app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += $(WERROR_FLAGS)
+
+# workaround for a gcc bug with noreturn attribute
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
+CFLAGS_main.o += -Wno-return-type
+endif
+
+CFLAGS += -O3
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/bond/main.c b/examples/bond/main.c
new file mode 100644
index 0000000..e4457f2
--- /dev/null
+++ b/examples/bond/main.c
@@ -0,0 +1,796 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 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 <stdint.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <termios.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_log.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_memcpy.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_arp.h>
+#include <rte_spinlock.h>
+
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "main.h"
+
+#include <rte_devargs.h>
+
+
+#include "rte_byteorder.h"
+#include "rte_cpuflags.h"
+#include "rte_eth_bond.h"
+
+#define RTE_LOGTYPE_DCB RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   (1024*8)
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100      /* TX drain every ~100us */
+#define BURST_RX_INTERVAL_NS (10) /* RX poll interval ~100ns */
+
+/*
+ * RX and TX Prefetch, Host, and Write-back threshold values should be
+ * carefully set for optimal performance. Consult the network
+ * controller's datasheet and supporting DPDK documentation for guidance
+ * on how these parameters should be set.
+ */
+#define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */
+#define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */
+#define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */
+#define RX_FTHRESH (MAX_PKT_BURST * 2)/**< Default values of RX free threshold reg. */
+
+/*
+ * These default values are optimized for use with the Intel(R) 82599 10 GbE
+ * Controller and the DPDK ixgbe PMD. Consider using other values for other
+ * network controllers and/or network drivers.
+ */
+#define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */
+#define TX_HTHRESH 0  /**< Default values of TX host threshold reg. */
+#define TX_WTHRESH 0  /**< Default values of TX write-back threshold reg. */
+
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_RX_DESC_DEFAULT 128
+#define RTE_TX_DESC_DEFAULT 512
+
+#define BOND_IP_1	7
+#define BOND_IP_2	0
+#define BOND_IP_3	0
+#define BOND_IP_4	10
+
+/* not defined under linux */
+#ifndef NIPQUAD
+#define NIPQUAD_FMT "%u.%u.%u.%u"
+#endif
+
+#define MAX_PORTS	4
+#define PRINT_MAC(addr)		printf("%02"PRIx8":%02"PRIx8":%02"PRIx8 \
+		":%02"PRIx8":%02"PRIx8":%02"PRIx8,	\
+		addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2], \
+		addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5])
+
+uint8_t slaves[RTE_MAX_ETHPORTS];
+uint8_t slaves_count;
+
+static uint8_t BOND_PORT = 0xff;
+
+static struct rte_mempool *mbuf_pool;
+
+static struct rte_eth_conf port_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 */
+	},
+	.rx_adv_conf = {
+		.rss_conf = {
+			.rss_key = NULL,
+			.rss_hf = ETH_RSS_IP,
+		},
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static void
+slave_port_init(uint8_t portid, struct rte_mempool *mbuf_pool)
+{
+	int retval;
+
+	if (portid >= rte_eth_dev_count())
+		rte_exit(EXIT_FAILURE, "Invalid port\n");
+
+	retval = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+	if (retval != 0)
+		rte_exit(EXIT_FAILURE, "port %u: configuration failed (res=%d)\n",
+				portid, retval);
+
+	/* RX setup */
+	retval = rte_eth_rx_queue_setup(portid, 0, RTE_RX_DESC_DEFAULT,
+					rte_eth_dev_socket_id(portid), NULL,
+					mbuf_pool);
+	if (retval < 0)
+		rte_exit(retval, " port %u: RX queue 0 setup failed (res=%d)",
+				portid, retval);
+
+	/* TX setup */
+	retval = rte_eth_tx_queue_setup(portid, 0, RTE_TX_DESC_DEFAULT,
+				rte_eth_dev_socket_id(portid), NULL);
+
+	if (retval < 0)
+		rte_exit(retval, "port %u: TX queue 0 setup failed (res=%d)",
+				portid, retval);
+
+	retval  = rte_eth_dev_start(portid);
+	if (retval < 0)
+		rte_exit(retval,
+				"Start port %d failed (res=%d)",
+				portid, retval);
+
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(portid, &addr);
+	printf("Port %u MAC: ", (unsigned)portid);
+	PRINT_MAC(addr);
+	printf("\n");
+}
+
+static void
+bond_port_init(struct rte_mempool *mbuf_pool)
+{
+	int retval;
+	uint8_t i;
+
+	retval = rte_eth_bond_create("bond0", BONDING_MODE_ALB,
+			0 /*SOCKET_ID_ANY*/);
+	if (retval < 0)
+		rte_exit(EXIT_FAILURE,
+				"Faled to create bond port\n");
+
+	BOND_PORT = (uint8_t)retval;
+
+	retval = rte_eth_dev_configure(BOND_PORT, 1, 1, &port_conf);
+	if (retval != 0)
+		rte_exit(EXIT_FAILURE, "port %u: configuration failed (res=%d)\n",
+				BOND_PORT, retval);
+
+	/* RX setup */
+	retval = rte_eth_rx_queue_setup(BOND_PORT, 0, RTE_RX_DESC_DEFAULT,
+					rte_eth_dev_socket_id(BOND_PORT), NULL,
+					mbuf_pool);
+	if (retval < 0)
+		rte_exit(retval, " port %u: RX queue 0 setup failed (res=%d)",
+				BOND_PORT, retval);
+
+	/* TX setup */
+	retval = rte_eth_tx_queue_setup(BOND_PORT, 0, RTE_TX_DESC_DEFAULT,
+				rte_eth_dev_socket_id(BOND_PORT), NULL);
+
+	if (retval < 0)
+		rte_exit(retval, "port %u: TX queue 0 setup failed (res=%d)",
+				BOND_PORT, retval);
+
+	for (i = 0; i < slaves_count; i++) {
+		if (rte_eth_bond_slave_add(BOND_PORT, slaves[i]) == -1)
+			rte_exit(-1, "Oooops! adding slave (%u) to bond (%u) failed!\n",
+					slaves[i], BOND_PORT);
+
+	}
+
+	retval  = rte_eth_dev_start(BOND_PORT);
+	if (retval < 0)
+		rte_exit(retval, "Start port %d failed (res=%d)", BOND_PORT, retval);
+
+	rte_eth_promiscuous_enable(BOND_PORT);
+
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(BOND_PORT, &addr);
+	printf("Port %u MAC: ", (unsigned)BOND_PORT);
+		PRINT_MAC(addr);
+		printf("\n");
+}
+
+static inline size_t
+get_vlan_offset(struct ether_hdr *eth_hdr, uint16_t *proto)
+{
+	size_t vlan_offset = 0;
+
+	if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
+
+		vlan_offset = sizeof(struct vlan_hdr);
+		*proto = vlan_hdr->eth_proto;
+
+		if (rte_cpu_to_be_16(ETHER_TYPE_VLAN) == *proto) {
+			vlan_hdr = vlan_hdr + 1;
+
+			*proto = vlan_hdr->eth_proto;
+			vlan_offset += sizeof(struct vlan_hdr);
+		}
+	}
+	return vlan_offset;
+}
+
+struct global_flag_stru_t {
+	int LcoreMainIsRunning;
+	int LcoreMainCore;
+	uint32_t port_packets[4];
+	rte_spinlock_t lock;
+};
+struct global_flag_stru_t global_flag_stru;
+struct global_flag_stru_t *global_flag_stru_p = &global_flag_stru;
+
+/*
+ * Main thread that does the work, reading from INPUT_PORT
+ * and writing to OUTPUT_PORT
+ */
+static int lcore_main(__attribute__((unused)) void *arg1)
+{
+	struct rte_mbuf *pkts[MAX_PKT_BURST] __rte_cache_aligned;
+	struct ether_addr d_addr;
+
+	struct ether_hdr *eth_hdr;
+	struct arp_hdr *arp_hdr;
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t ether_type, offset;
+
+	uint16_t rx_cnt;
+	uint32_t bond_ip;
+	int i = 0;
+	uint8_t is_free;
+
+	bond_ip = BOND_IP_1 | (BOND_IP_2 << 8) |
+				(BOND_IP_3 << 16) | (BOND_IP_4 << 24);
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+
+	while (global_flag_stru_p->LcoreMainIsRunning) {
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		rx_cnt = rte_eth_rx_burst(BOND_PORT, 0, pkts, MAX_PKT_BURST);
+		is_free = 0;
+
+		/* If didn't receive any packets, wait and go to next iteration */
+		if (rx_cnt == 0) {
+			rte_delay_us(50);
+			continue;
+		}
+
+		/* Search incoming data for ARP packets and prepare response */
+		for (i = 0; i < rx_cnt; i++) {
+			if (rte_spinlock_trylock(&global_flag_stru_p->lock) == 1) {
+				global_flag_stru_p->port_packets[0]++;
+				rte_spinlock_unlock(&global_flag_stru_p->lock);
+			}
+			eth_hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+			ether_type = eth_hdr->ether_type;
+			if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_VLAN))
+				printf("VLAN taged frame, offset:");
+			offset = get_vlan_offset(eth_hdr, &ether_type);
+			if (offset > 0)
+				printf("%d\n", offset);
+			if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+				if (rte_spinlock_trylock(&global_flag_stru_p->lock) == 1)     {
+					global_flag_stru_p->port_packets[1]++;
+					rte_spinlock_unlock(&global_flag_stru_p->lock);
+				}
+				arp_hdr = (struct arp_hdr *)((char *)(eth_hdr + 1) + offset);
+				if (arp_hdr->arp_data.arp_tip == bond_ip) {
+					if (arp_hdr->arp_op == rte_cpu_to_be_16(ARP_OP_REQUEST)) {
+						arp_hdr->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
+						/* Switch src and dst data and set bonding MAC */
+						ether_addr_copy(&eth_hdr->s_addr, &eth_hdr->d_addr);
+						rte_eth_macaddr_get(BOND_PORT, &eth_hdr->s_addr);
+						ether_addr_copy(&arp_hdr->arp_data.arp_sha, &arp_hdr->arp_data.arp_tha);
+						arp_hdr->arp_data.arp_tip = arp_hdr->arp_data.arp_sip;
+						rte_eth_macaddr_get(BOND_PORT, &d_addr);
+						ether_addr_copy(&d_addr, &arp_hdr->arp_data.arp_sha);
+						arp_hdr->arp_data.arp_sip = bond_ip;
+						rte_eth_tx_burst(BOND_PORT, 0, &pkts[i], 1);
+						is_free = 1;
+					} else {
+						rte_eth_tx_burst(BOND_PORT, 0, NULL, 0);
+					}
+				}
+			} else if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+				if (rte_spinlock_trylock(&global_flag_stru_p->lock) == 1)     {
+					global_flag_stru_p->port_packets[2]++;
+					rte_spinlock_unlock(&global_flag_stru_p->lock);
+				 }
+				ipv4_hdr = (struct ipv4_hdr *)((char *)(eth_hdr + 1) + offset);
+				if (ipv4_hdr->dst_addr == bond_ip) {
+					ether_addr_copy(&eth_hdr->s_addr, &eth_hdr->d_addr);
+					rte_eth_macaddr_get(BOND_PORT, &eth_hdr->s_addr);
+					ipv4_hdr->dst_addr = ipv4_hdr->src_addr;
+					ipv4_hdr->src_addr = bond_ip;
+					rte_eth_tx_burst(BOND_PORT, 0, &pkts[i], 1);
+				}
+
+			}
+
+			/* Free processed packets */
+			if (is_free == 0)
+				rte_pktmbuf_free(pkts[i]);
+		}
+		rte_spinlock_trylock(&global_flag_stru_p->lock);
+	}
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+	printf("BYE lcore_main\n");
+	return 0;
+}
+
+struct cmd_obj_send_result {
+	cmdline_fixed_string_t action;
+	cmdline_ipaddr_t ip;
+};
+static inline void get_string(struct cmd_obj_send_result *res, char *buf, uint8_t size)
+{
+	snprintf(buf, size, NIPQUAD_FMT,
+		((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[0]),
+		((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[1]),
+		((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[2]),
+		((unsigned)((unsigned char *)&(res->ip.addr.ipv4))[3])
+		);
+}
+static void cmd_obj_send_parsed(void *parsed_result,
+		__attribute__((unused)) struct cmdline *cl,
+			       __attribute__((unused)) void *data)
+{
+
+	struct cmd_obj_send_result *res = parsed_result;
+	char ip_str[INET6_ADDRSTRLEN];
+
+	struct rte_mbuf *created_pkt;
+	struct ether_hdr *eth_hdr;
+	struct arp_hdr *arp_hdr;
+
+	uint32_t bond_ip;
+	size_t pkt_size;
+
+	if (res->ip.family == AF_INET)
+		get_string(res, ip_str, INET_ADDRSTRLEN);
+	else
+		cmdline_printf(cl, "Wrong IP format. Only IPv4 is supported\n");
+
+	bond_ip = BOND_IP_1 | (BOND_IP_2 << 8) |
+				(BOND_IP_3 << 16) | (BOND_IP_4 << 24);
+
+	created_pkt = rte_pktmbuf_alloc(mbuf_pool);
+	pkt_size = sizeof(struct ether_hdr) + sizeof(struct arp_hdr);
+	created_pkt->data_len = pkt_size;
+	created_pkt->pkt_len = pkt_size;
+
+	eth_hdr = rte_pktmbuf_mtod(created_pkt, struct ether_hdr *);
+	rte_eth_macaddr_get(BOND_PORT, &eth_hdr->s_addr);
+	memset(&eth_hdr->d_addr, 0xFF, ETHER_ADDR_LEN);
+	eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+
+	arp_hdr = (struct arp_hdr *)((char *)eth_hdr + sizeof(struct ether_hdr));
+	arp_hdr->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
+	arp_hdr->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	arp_hdr->arp_hln = ETHER_ADDR_LEN;
+	arp_hdr->arp_pln = sizeof(uint32_t);
+	arp_hdr->arp_op = rte_cpu_to_be_16(ARP_OP_REQUEST);
+
+	rte_eth_macaddr_get(BOND_PORT, &arp_hdr->arp_data.arp_sha);
+	arp_hdr->arp_data.arp_sip = bond_ip;
+	memset(&arp_hdr->arp_data.arp_tha, 0, ETHER_ADDR_LEN);
+	arp_hdr->arp_data.arp_tip =
+			  ((unsigned char *)&res->ip.addr.ipv4)[0]        |
+			 (((unsigned char *)&res->ip.addr.ipv4)[1] << 8)  |
+			 (((unsigned char *)&res->ip.addr.ipv4)[2] << 16) |
+			 (((unsigned char *)&res->ip.addr.ipv4)[3] << 24);
+	rte_eth_tx_burst(BOND_PORT, 0, &created_pkt, 1);
+
+	rte_delay_ms(100);
+	cmdline_printf(cl, "\n");
+}
+
+cmdline_parse_token_string_t cmd_obj_action_send =
+	TOKEN_STRING_INITIALIZER(struct cmd_obj_send_result, action, "send");
+cmdline_parse_token_ipaddr_t cmd_obj_ip =
+	TOKEN_IPV4_INITIALIZER(struct cmd_obj_send_result, ip);
+
+cmdline_parse_inst_t cmd_obj_send = {
+	.f = cmd_obj_send_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "send client_ip",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_obj_action_send,
+		(void *)&cmd_obj_ip,
+		NULL,
+	},
+};
+
+struct cmd_start_result {
+	cmdline_fixed_string_t start;
+};
+
+static void cmd_start_parsed(__attribute__((unused)) void *parsed_result,
+			       struct cmdline *cl,
+			       __attribute__((unused)) void *data)
+{
+	int slave_core_id = rte_lcore_id();
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	if (global_flag_stru_p->LcoreMainIsRunning == 0)	{
+		if (lcore_config[global_flag_stru_p->LcoreMainCore].state != WAIT)	{
+			rte_spinlock_unlock(&global_flag_stru_p->lock);
+			return;
+		}
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+	} else {
+		cmdline_printf(cl, "lcore_main already running on core:%d\n",
+				global_flag_stru_p->LcoreMainCore);
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		return;
+	}
+
+	/* start lcore main on core != master_core - ARP response thread */
+	slave_core_id = rte_get_next_lcore(rte_lcore_id(), 1, 0);
+	if ((slave_core_id >= RTE_MAX_LCORE) || (slave_core_id == 0))
+		return;
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	global_flag_stru_p->LcoreMainIsRunning = 1;
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+	cmdline_printf(cl,
+			"Starting lcore_main on core %d:%d "
+			"Our IP:%d.%d.%d.%d\n",
+			slave_core_id,
+			rte_eal_remote_launch(lcore_main, NULL, slave_core_id),
+			BOND_IP_1,
+			BOND_IP_2,
+			BOND_IP_3,
+			BOND_IP_4
+		);
+}
+
+cmdline_parse_token_string_t cmd_start_start =
+	TOKEN_STRING_INITIALIZER(struct cmd_start_result, start, "start");
+
+cmdline_parse_inst_t cmd_start = {
+	.f = cmd_start_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "starts listening if not started at startup",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_start_start,
+		NULL,
+	},
+};
+
+struct cmd_help_result {
+	cmdline_fixed_string_t help;
+};
+
+static void cmd_help_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	cmdline_printf(cl,
+			"ALB - link bonding mode 6 example\n"
+			"send IP	- sends one ARPrequest thru bonding for IP.\n"
+			"start		- starts listening ARPs.\n"
+			"stop		- stops lcore_main.\n"
+			"show		- shows some bond info: ex. active slaves etc.\n"
+			"help		- prints help.\n"
+			"quit		- terminate all threads and quit.\n"
+		       );
+}
+
+cmdline_parse_token_string_t cmd_help_help =
+	TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
+
+cmdline_parse_inst_t cmd_help = {
+	.f = cmd_help_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "show help",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_help_help,
+		NULL,
+	},
+};
+
+struct cmd_stop_result {
+	cmdline_fixed_string_t stop;
+};
+
+static void cmd_stop_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	if (global_flag_stru_p->LcoreMainIsRunning == 0)	{
+		cmdline_printf(cl,
+					"lcore_main not running on core:%d\n",
+					global_flag_stru_p->LcoreMainCore);
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		return;
+	}
+	global_flag_stru_p->LcoreMainIsRunning = 0;
+	rte_eal_wait_lcore(global_flag_stru_p->LcoreMainCore);
+	cmdline_printf(cl,
+			"lcore_main stopped on core:%d\n",
+			global_flag_stru_p->LcoreMainCore);
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+}
+
+cmdline_parse_token_string_t cmd_stop_stop =
+	TOKEN_STRING_INITIALIZER(struct cmd_stop_result, stop, "stop");
+
+cmdline_parse_inst_t cmd_stop = {
+	.f = cmd_stop_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "this command do not handle any arguments",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_stop_stop,
+		NULL,
+	},
+};
+
+struct cmd_quit_result {
+	cmdline_fixed_string_t quit;
+};
+
+static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	if (global_flag_stru_p->LcoreMainIsRunning == 0)	{
+		cmdline_printf(cl,
+					"lcore_main not running on core:%d\n",
+					global_flag_stru_p->LcoreMainCore);
+		rte_spinlock_unlock(&global_flag_stru_p->lock);
+		cmdline_quit(cl);
+		return;
+	}
+	global_flag_stru_p->LcoreMainIsRunning = 0;
+	rte_eal_wait_lcore(global_flag_stru_p->LcoreMainCore);
+	cmdline_printf(cl,
+			"lcore_main stopped on core:%d\n",
+			global_flag_stru_p->LcoreMainCore);
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+	cmdline_quit(cl);
+}
+
+cmdline_parse_token_string_t cmd_quit_quit =
+	TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
+
+cmdline_parse_inst_t cmd_quit = {
+	.f = cmd_quit_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "this command do not handle any arguments",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_quit_quit,
+		NULL,
+	},
+};
+
+extern void print_client_stats(void);
+struct cmd_show_result {
+	cmdline_fixed_string_t show;
+};
+
+static void cmd_show_parsed(__attribute__((unused)) void *parsed_result,
+			    struct cmdline *cl,
+			    __attribute__((unused)) void *data)
+{
+	uint8_t slaves[16] = {0};
+	uint8_t len = 16;
+	struct ether_addr addr;
+	uint8_t i = 0;
+
+	while (i < slaves_count)	{
+		rte_eth_macaddr_get(i, &addr);
+		PRINT_MAC(addr);
+		printf("\n");
+		i++;
+	}
+
+	rte_spinlock_trylock(&global_flag_stru_p->lock);
+	cmdline_printf(cl,
+			"Active_slaves:%d "
+			"packets received:Tot:%d Arp:%d IPv4:%d\n",
+			rte_eth_bond_active_slaves_get(BOND_PORT, slaves, len),
+			global_flag_stru_p->port_packets[0],
+			global_flag_stru_p->port_packets[1],
+			global_flag_stru_p->port_packets[2]);
+	rte_spinlock_unlock(&global_flag_stru_p->lock);
+
+#if defined(RTE_LIBRTE_BOND_DEBUG_ALB_L1) || defined(RTE_LIBRTE_BOND_DEBUG_ALB)
+	print_client_stats();
+#endif
+}
+
+cmdline_parse_token_string_t cmd_show_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_result, show, "show");
+
+cmdline_parse_inst_t cmd_show = {
+	.f = cmd_show_parsed,  /* function to call */
+	.data = NULL,      /* 2nd arg of func */
+	.help_str = "this command do not handle any arguments",
+	.tokens = {        /* token list, NULL terminated */
+		(void *)&cmd_show_show,
+		NULL,
+	},
+};
+
+/****** CONTEXT (list of instruction) */
+
+cmdline_parse_ctx_t main_ctx[] = {
+	(cmdline_parse_inst_t *)&cmd_start,
+	(cmdline_parse_inst_t *)&cmd_obj_send,
+	(cmdline_parse_inst_t *)&cmd_stop,
+	(cmdline_parse_inst_t *)&cmd_show,
+	(cmdline_parse_inst_t *)&cmd_quit,
+	(cmdline_parse_inst_t *)&cmd_help,
+	NULL,
+};
+
+/* prompt function, called from main on MASTER lcore */
+static void *prompt(__attribute__((unused)) void *arg1)
+{
+	struct cmdline *cl;
+
+	cl = cmdline_stdin_new(main_ctx, "bond6>");
+	if (cl != NULL) {
+		cmdline_interact(cl);
+		cmdline_stdin_exit(cl);
+	}
+}
+
+/* Main function, does initialisation and calls the per-lcore functions */
+int
+main(int argc, char *argv[])
+{
+	int ret;
+	uint8_t nb_ports, i;
+
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	rte_eal_devargs_dump(stdout);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
+	argc -= ret;
+	argv += ret;
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "Give at least one port\n");
+	else if (nb_ports > MAX_PORTS)
+		rte_exit(EXIT_FAILURE, "You can have max 4 ports\n");
+
+	mbuf_pool = rte_mempool_create("MBUF_POOL", NB_MBUF,
+				       MBUF_SIZE, 32,
+				       sizeof(struct rte_pktmbuf_pool_private),
+				       rte_pktmbuf_pool_init, NULL,
+				       rte_pktmbuf_init, NULL,
+				       rte_socket_id(), 0);
+	if (mbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
+
+	/* initialize all ports */
+	slaves_count = nb_ports;
+	for (i = 0; i < nb_ports; i++) {
+		slave_port_init(i, mbuf_pool);
+		slaves[i] = i;
+	}
+
+	bond_port_init(mbuf_pool);
+
+	rte_spinlock_init(&global_flag_stru_p->lock);
+	int slave_core_id = rte_lcore_id();
+
+	/* check state of lcores */
+	RTE_LCORE_FOREACH_SLAVE(slave_core_id) {
+	if (lcore_config[slave_core_id].state != WAIT)
+		return -EBUSY;
+	}
+	/* start lcore main on core != master_core - ARP response thread */
+	slave_core_id = rte_get_next_lcore(rte_lcore_id(), 1, 0);
+	if ((slave_core_id >= RTE_MAX_LCORE) || (slave_core_id == 0))
+		return -EPERM;
+
+	global_flag_stru_p->LcoreMainIsRunning = 1;
+	global_flag_stru_p->LcoreMainCore = slave_core_id;
+	printf("Starting lcore_main on core %d:%d Our IP:%d.%d.%d.%d\n",
+			slave_core_id,
+			rte_eal_remote_launch((lcore_function_t *)lcore_main,
+					NULL,
+					slave_core_id),
+			BOND_IP_1,
+			BOND_IP_2,
+			BOND_IP_3,
+			BOND_IP_4
+		);
+
+	/* Start prompt for user interact */
+	prompt(NULL);
+
+	rte_delay_ms(100);
+	return 0;
+}
diff --git a/examples/bond/main.h b/examples/bond/main.h
new file mode 100644
index 0000000..ea331e5
--- /dev/null
+++ b/examples/bond/main.h
@@ -0,0 +1,39 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 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 _MAIN_H_
+#define _MAIN_H_
+
+int main(int argc, char *argv[]);
+
+#endif /* ifndef _MAIN_H_ */
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v4 5/6] bond: modify TLB unit tests
  2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                     ` (3 preceding siblings ...)
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
@ 2015-02-20 16:09   ` Michal Jastrzebski
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 6/6] bond: add unit tests for link bonding mode 6 Michal Jastrzebski
  2015-02-20 17:44   ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Declan Doherty
  6 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-20 16:09 UTC (permalink / raw)
  To: dev

From: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>

This patch modify mode older name from
BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING to BONDING_MODE_TLB
This patch also changes order of TEST_ASSERT macro in
test_tlb_verify_slave_link_status_change_failover.

Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
---
 app/test/test_link_bonding.c            |   27 ++++++++++++++-------------
 lib/librte_pmd_bond/rte_eth_bond.h      |    2 +-
 lib/librte_pmd_bond/rte_eth_bond_api.c  |    8 ++++----
 lib/librte_pmd_bond/rte_eth_bond_args.c |    2 +-
 lib/librte_pmd_bond/rte_eth_bond_pmd.c  |   12 ++++++------
 5 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index 579ebbf..dd6e357 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -4053,7 +4053,7 @@ test_tlb_tx_burst(void)
 	uint64_t floor_obytes = 0, ceiling_obytes = 0;
 
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves
-			(BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 1, 3, 1),
+			(BONDING_MODE_TLB, 1, 3, 1),
 			"Failed to initialise bonded device");
 
 	burst_size = 20 * test_params->bonded_slave_count;
@@ -4153,7 +4153,7 @@ test_tlb_rx_burst(void)
 
 	/* Initialize bonded device with 4 slaves in transmit load balancing mode */
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING,
+			BONDING_MODE_TLB,
 			TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1, 1),
 			"Failed to initialize bonded device");
 
@@ -4231,7 +4231,7 @@ test_tlb_verify_promiscuous_enable_disable(void)
 
 	/* Initialize bonded device with 4 slaves in transmit load balancing mode */
 	TEST_ASSERT_SUCCESS( initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 4, 1),
+			BONDING_MODE_TLB, 0, 4, 1),
 			"Failed to initialize bonded device");
 
 	primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id);
@@ -4289,7 +4289,7 @@ test_tlb_verify_mac_assignment(void)
 
 	/* Initialize bonded device with 2 slaves in active backup mode */
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0, 2, 1),
+			BONDING_MODE_TLB, 0, 2, 1),
 			"Failed to initialize bonded device");
 
 	/* Verify that bonded MACs is that of first slave and that the other slave
@@ -4409,7 +4409,7 @@ test_tlb_verify_slave_link_status_change_failover(void)
 
 	/* Initialize bonded device with 4 slaves in round robin mode */
 	TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves(
-			BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING, 0,
+			BONDING_MODE_TLB, 0,
 			TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1),
 			"Failed to initialize bonded device with slaves");
 
@@ -4472,20 +4472,21 @@ test_tlb_verify_slave_link_status_change_failover(void)
 		rte_delay_us(11000);
 	}
 
-	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
-	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
-			"(%d) port_stats.opackets not as expected\n",
-			test_params->slave_port_ids[2]);
-
 	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
 	TEST_ASSERT_EQUAL(port_stats.opackets, (int8_t)0,
-			"(%d) port_stats.opackets not as expected\n",
-			test_params->slave_port_ids[0]);
+				"(%d) port_stats.opackets not as expected\n",
+				test_params->slave_port_ids[0]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
+					"(%d) port_stats.opackets not as expected\n",
+					test_params->slave_port_ids[1]);
+
+
+	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
+	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
 			"(%d) port_stats.opackets not as expected\n",
-			test_params->slave_port_ids[1]);
+			test_params->slave_port_ids[2]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
diff --git a/lib/librte_pmd_bond/rte_eth_bond.h b/lib/librte_pmd_bond/rte_eth_bond.h
index 13581cb..4117a70 100644
--- a/lib/librte_pmd_bond/rte_eth_bond.h
+++ b/lib/librte_pmd_bond/rte_eth_bond.h
@@ -96,7 +96,7 @@ extern "C" {
  * to rx_burst should be at least 2 times the slave count size.
  *
  */
-#define BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING	(5)
+#define BONDING_MODE_TLB	(5)
 /**< Adaptive TLB (Mode 5)
  * This mode provides an adaptive transmit load balancing. It dynamically
  * changes the transmitting slave, according to the computed load. Statistics
diff --git a/lib/librte_pmd_bond/rte_eth_bond_api.c b/lib/librte_pmd_bond/rte_eth_bond_api.c
index cbfd185..a5f2c26 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_api.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_api.c
@@ -116,7 +116,7 @@ activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_activate_slave(eth_dev, port_id);
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+	if (internals->mode == BONDING_MODE_TLB
 			|| internals->mode == BONDING_MODE_ALB) {
 
 		internals->tlb_slaves_order[active_count] = port_id;
@@ -128,7 +128,7 @@ activate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	internals->active_slaves[internals->active_slave_count] = port_id;
 	internals->active_slave_count++;
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING)
+	if (internals->mode == BONDING_MODE_TLB)
 		bond_tlb_activate_slave(internals);
 	if (internals->mode == BONDING_MODE_ALB)
 		bond_mode_alb_client_list_upd(eth_dev);
@@ -144,7 +144,7 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (internals->mode == BONDING_MODE_8023AD) {
 		bond_mode_8023ad_stop(eth_dev);
 		bond_mode_8023ad_deactivate_slave(eth_dev, port_id);
-	} else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING
+	} else if (internals->mode == BONDING_MODE_TLB
 			|| internals->mode == BONDING_MODE_ALB)
 		bond_tlb_disable(internals);
 
@@ -167,7 +167,7 @@ deactivate_slave(struct rte_eth_dev *eth_dev, uint8_t port_id)
 	if (eth_dev->data->dev_started) {
 	   if (internals->mode == BONDING_MODE_8023AD) {
 			   bond_mode_8023ad_start(eth_dev);
-	   } else if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING) {
+	   } else if (internals->mode == BONDING_MODE_TLB) {
 			   bond_tlb_enable(internals);
 	   } else if (internals->mode == BONDING_MODE_ALB) {
 			   bond_tlb_enable(internals);
diff --git a/lib/librte_pmd_bond/rte_eth_bond_args.c b/lib/librte_pmd_bond/rte_eth_bond_args.c
index a3f7f55..0801cb5 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_args.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_args.c
@@ -174,7 +174,7 @@ bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,
 	case BONDING_MODE_BROADCAST:
 #endif
 	case BONDING_MODE_8023AD:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 		return 0;
 	default:
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index af2ef8c..b1040a4 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -1225,7 +1225,7 @@ mac_address_slaves_update(struct rte_eth_dev *bonded_eth_dev)
 		bond_mode_8023ad_mac_address_update(bonded_eth_dev);
 		break;
 	case BONDING_MODE_ACTIVE_BACKUP:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 	default:
 		for (i = 0; i < internals->slave_count; i++) {
@@ -1288,7 +1288,7 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
 				"Using mode 4, it is necessary to do TX burst and RX burst "
 				"at least every 100ms.");
 		break;
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 		eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb;
 		eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_active_backup;
 		break;
@@ -1514,7 +1514,7 @@ bond_ethdev_start(struct rte_eth_dev *eth_dev)
 	if (internals->mode == BONDING_MODE_8023AD)
 		bond_mode_8023ad_start(eth_dev);
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+	if (internals->mode == BONDING_MODE_TLB ||
 			internals->mode == BONDING_MODE_ALB)
 		bond_tlb_enable(internals);
 
@@ -1547,7 +1547,7 @@ bond_ethdev_stop(struct rte_eth_dev *eth_dev)
 		}
 	}
 
-	if (internals->mode == BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING ||
+	if (internals->mode == BONDING_MODE_TLB ||
 			internals->mode == BONDING_MODE_ALB) {
 		bond_tlb_disable(internals);
 		for (i = 0; i < internals->active_slave_count; i++)
@@ -1807,7 +1807,7 @@ bond_ethdev_promiscuous_enable(struct rte_eth_dev *eth_dev)
 		break;
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_enable(internals->current_primary_port);
@@ -1837,7 +1837,7 @@ bond_ethdev_promiscuous_disable(struct rte_eth_dev *dev)
 		break;
 	/* Promiscuous mode is propagated only to primary slave */
 	case BONDING_MODE_ACTIVE_BACKUP:
-	case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
+	case BONDING_MODE_TLB:
 	case BONDING_MODE_ALB:
 	default:
 		rte_eth_promiscuous_disable(internals->current_primary_port);
-- 
1.7.9.5

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

* [dpdk-dev] [PATCH v4 6/6] bond: add unit tests for link bonding mode 6.
  2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                     ` (4 preceding siblings ...)
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 5/6] bond: modify TLB unit tests Michal Jastrzebski
@ 2015-02-20 16:09   ` Michal Jastrzebski
  2015-02-20 17:44   ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Declan Doherty
  6 siblings, 0 replies; 35+ messages in thread
From: Michal Jastrzebski @ 2015-02-20 16:09 UTC (permalink / raw)
  To: dev

From: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>

Added 4 unit tests checking link bonding mode 6 behavior.

Also modified virtual_pmd so it is possible to provide packets,
that should be received with rx_burst and to inspect packets
transmitted by tx_burst.

In packet_burst_generator.c function creating eth_header is
modified, so it accepts ether_type as a parameter and function
creating arp_header is added. Updated other unit tests to get
rid of compilation errors.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
---
 app/test/packet_burst_generator.c |   41 +++-
 app/test/packet_burst_generator.h |   11 +-
 app/test/test_link_bonding.c      |  439 +++++++++++++++++++++++++++++++++++--
 app/test/test_pmd_perf.c          |    3 +-
 app/test/virtual_pmd.c            |  109 +++++----
 app/test/virtual_pmd.h            |    5 +-
 6 files changed, 533 insertions(+), 75 deletions(-)

diff --git a/app/test/packet_burst_generator.c b/app/test/packet_burst_generator.c
index e9d059c..b46eed7 100644
--- a/app/test/packet_burst_generator.c
+++ b/app/test/packet_burst_generator.c
@@ -80,11 +80,10 @@ copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
 	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 ipv4, uint8_t vlan_enabled,
-		uint16_t van_id)
+		struct ether_addr *dst_mac, uint16_t ether_type,
+		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);
@@ -95,19 +94,27 @@ initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
 
 		eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
 
-		if (ipv4)
-			vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv4);
-		else
-			vhdr->eth_proto =  rte_cpu_to_be_16(ETHER_TYPE_IPv6);
-
+		vhdr->eth_proto =  rte_cpu_to_be_16(ether_type);
 		vhdr->vlan_tci = van_id;
 	} else {
-		if (ipv4)
-			eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
-		else
-			eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		eth_hdr->ether_type = rte_cpu_to_be_16(ether_type);
 	}
+}
 
+void
+initialize_arp_header(struct arp_hdr *arp_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint32_t src_ip, uint32_t dst_ip,
+		uint32_t opcode)
+{
+	arp_hdr->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER);
+	arp_hdr->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	arp_hdr->arp_hln = ETHER_ADDR_LEN;
+	arp_hdr->arp_pln = sizeof(uint32_t);
+	arp_hdr->arp_op = rte_cpu_to_be_16(opcode);
+	ether_addr_copy(src_mac, &arp_hdr->arp_data.arp_sha);
+	arp_hdr->arp_data.arp_sip = src_ip;
+	ether_addr_copy(dst_mac, &arp_hdr->arp_data.arp_tha);
+	arp_hdr->arp_data.arp_tip = dst_ip;
 }
 
 uint16_t
@@ -265,9 +272,19 @@ nomore_mbuf:
 		if (ipv4) {
 			pkt->vlan_tci  = ETHER_TYPE_IPv4;
 			pkt->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->vlan_tci  = ETHER_TYPE_IPv6;
 			pkt->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;
diff --git a/app/test/packet_burst_generator.h b/app/test/packet_burst_generator.h
index 666cc8e..edc1044 100644
--- a/app/test/packet_burst_generator.h
+++ b/app/test/packet_burst_generator.h
@@ -40,6 +40,7 @@ extern "C" {
 
 #include <rte_mbuf.h>
 #include <rte_ether.h>
+#include <rte_arp.h>
 #include <rte_ip.h>
 #include <rte_udp.h>
 
@@ -50,11 +51,15 @@ extern "C" {
 #define PACKET_BURST_GEN_PKT_LEN 60
 #define PACKET_BURST_GEN_PKT_LEN_128 128
 
-
 void
 initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac,
-		struct ether_addr *dst_mac, uint8_t ipv4, uint8_t vlan_enabled,
-		uint16_t van_id);
+		struct ether_addr *dst_mac, uint16_t ether_type,
+		uint8_t vlan_enabled, uint16_t van_id);
+
+void
+initialize_arp_header(struct arp_hdr *arp_hdr, struct ether_addr *src_mac,
+		struct ether_addr *dst_mac, uint32_t src_ip, uint32_t dst_ip,
+		uint32_t opcode);
 
 uint16_t
 initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index dd6e357..0a37125 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -1313,17 +1313,22 @@ 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;
+	uint16_t pktlen, generated_burst_size, ether_type;
 	void *ip_hdr;
 
+	if (ipv4)
+		ether_type = ETHER_TYPE_IPv4;
+	else
+		ether_type = ETHER_TYPE_IPv6;
+
 	if (toggle_dst_mac)
 		initialize_eth_header(test_params->pkt_eth_hdr,
 				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
-				ipv4, vlan, vlan_id);
+				ether_type, vlan, vlan_id);
 	else
 		initialize_eth_header(test_params->pkt_eth_hdr,
 				(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
-				ipv4, vlan, vlan_id);
+				ether_type, vlan, vlan_id);
 
 
 	if (toggle_udp_port)
@@ -2094,7 +2099,8 @@ test_activebackup_tx_burst(void)
 			"Failed to initialize bonded device with slaves");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+			ETHER_TYPE_IPv4,  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,
@@ -2637,7 +2643,8 @@ test_balance_l2_tx_burst(void)
 			"Failed to set balance xmit policy.");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+			ETHER_TYPE_IPv4, 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,
@@ -2651,7 +2658,8 @@ test_balance_l2_tx_burst(void)
 			"failed to generate packet burst");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1,
+			ETHER_TYPE_IPv4, 0, 0);
 
 	/* Generate a burst 2 of packets to transmit */
 	TEST_ASSERT_EQUAL(generate_packet_burst(test_params->mbuf_pool, &pkts_burst[1][0],
@@ -3488,7 +3496,8 @@ test_broadcast_tx_burst(void)
 			"Failed to intialise bonded device");
 
 	initialize_eth_header(test_params->pkt_eth_hdr,
-			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, 1, 0, 0);
+			(struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0,
+			ETHER_TYPE_IPv4, 0, 0);
 
 	pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
 			dst_port_0, 16);
@@ -4041,6 +4050,23 @@ testsuite_teardown(void)
 	return remove_slaves_and_stop_bonded_device();
 }
 
+static void
+free_virtualpmd_tx_queue(void)
+{
+	int i, slave_port, to_free_cnt;
+	struct rte_mbuf *pkts_to_free[MAX_PKT_BURST];
+
+	/* Free tx queue of virtual pmd */
+	for (slave_port = 0; slave_port < test_params->bonded_slave_count;
+			slave_port++) {
+		to_free_cnt = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_port],
+				pkts_to_free, MAX_PKT_BURST);
+		for (i = 0; i < to_free_cnt; i++)
+			rte_pktmbuf_free(pkts_to_free[i]);
+	}
+}
+
 static int
 test_tlb_tx_burst(void)
 {
@@ -4068,11 +4094,11 @@ test_tlb_tx_burst(void)
 		if (i % 2 == 0) {
 			initialize_eth_header(test_params->pkt_eth_hdr,
 					(struct ether_addr *)src_mac,
-					(struct ether_addr *)dst_mac_0, 1, 0, 0);
+					(struct ether_addr *)dst_mac_0, ETHER_TYPE_IPv4, 0, 0);
 		} else {
 			initialize_eth_header(test_params->pkt_eth_hdr,
 					(struct ether_addr *)test_params->default_slave_mac,
-					(struct ether_addr *)dst_mac_0, 1, 0, 0);
+					(struct ether_addr *)dst_mac_0, ETHER_TYPE_IPv4, 0, 0);
 		}
 		pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port,
 				dst_port_0, 16);
@@ -4086,6 +4112,8 @@ test_tlb_tx_burst(void)
 				burst_size);
 		nb_tx2 += nb_tx;
 
+		free_virtualpmd_tx_queue();
+
 		TEST_ASSERT_EQUAL(nb_tx, burst_size,
 				"number of packet not equal burst size");
 
@@ -4474,14 +4502,13 @@ test_tlb_verify_slave_link_status_change_failover(void)
 
 	rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats);
 	TEST_ASSERT_EQUAL(port_stats.opackets, (int8_t)0,
-				"(%d) port_stats.opackets not as expected\n",
-				test_params->slave_port_ids[0]);
+			"(%d) port_stats.opackets not as expected\n",
+			test_params->slave_port_ids[0]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
-					"(%d) port_stats.opackets not as expected\n",
-					test_params->slave_port_ids[1]);
-
+			"(%d) port_stats.opackets not as expected\n",
+			test_params->slave_port_ids[1]);
 
 	rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats);
 	TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0,
@@ -4534,6 +4561,386 @@ test_tlb_verify_slave_link_status_change_failover(void)
 	return remove_slaves_and_stop_bonded_device();
 }
 
+#define TEST_ALB_SLAVE_COUNT	2
+
+static uint8_t mac_client1[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 1};
+static uint8_t mac_client2[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 2};
+static uint8_t mac_client3[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 3};
+static uint8_t mac_client4[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 4};
+
+static uint32_t ip_host = IPV4_ADDR(192, 168, 0, 0);
+static uint32_t ip_client1 = IPV4_ADDR(192, 168, 0, 1);
+static uint32_t ip_client2 = IPV4_ADDR(192, 168, 0, 2);
+static uint32_t ip_client3 = IPV4_ADDR(192, 168, 0, 3);
+static uint32_t ip_client4 = IPV4_ADDR(192, 168, 0, 4);
+
+static int
+test_alb_change_mac_in_reply_sent(void)
+{
+	struct rte_mbuf *pkt;
+	struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+	struct ether_hdr *eth_pkt;
+	struct arp_hdr *arp_pkt;
+
+	int slave_idx, nb_pkts, pkt_idx;
+	int retval = 0;
+
+	struct ether_addr bond_mac, client_mac;
+	struct ether_addr *slave_mac1, *slave_mac2;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	/* Flush tx queue */
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count;
+			slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+	}
+
+	ether_addr_copy(
+			rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+			&bond_mac);
+
+	/*
+	 * Generating four packets with different mac and ip addresses and sending
+	 * them through the bonding port.
+	 */
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client1,
+			ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client2,
+			ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client3,
+			ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client4,
+			ARP_OP_REPLY);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1);
+
+	slave_mac1 =
+			rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs;
+	slave_mac2 =
+			rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs;
+
+	/*
+	 * Checking if packets are properly distributed on bonding ports. Packets
+	 * 0 and 2 should be sent on port 0 and packets 1 and 3 on port 1.
+	 */
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+
+		for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+			eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+			arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+
+			if (slave_idx%2 == 0) {
+				if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			} else {
+				if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			}
+		}
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
+
+static int
+test_alb_reply_from_client(void)
+{
+	struct ether_hdr *eth_pkt;
+	struct arp_hdr *arp_pkt;
+
+	struct rte_mbuf *pkt;
+	struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+	int slave_idx, nb_pkts, pkt_idx, nb_pkts_sum = 0;
+	int retval = 0;
+
+	struct ether_addr bond_mac, client_mac;
+	struct ether_addr *slave_mac1, *slave_mac2;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	/* Flush tx queue */
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+	}
+
+	ether_addr_copy(
+			rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+			&bond_mac);
+
+	/*
+	 * Generating four packets with different mac and ip addresses and placing
+	 * them in the rx queue to be received by the bonding driver on rx_burst.
+	 */
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client2, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client3, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0,
+			0);
+	arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client4, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	/*
+	 * Issue rx_burst and tx_burst to force bonding driver to send update ARP
+	 * packets to every client in alb table.
+	 */
+	rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+
+	slave_mac1 = rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs;
+	slave_mac2 = rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs;
+
+	/*
+	 * Checking if update ARP packets were properly send on slave ports.
+	 */
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent, MAX_PKT_BURST);
+		nb_pkts_sum += nb_pkts;
+
+		for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+			eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+			arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr));
+
+			if (slave_idx%2 == 0) {
+				if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			} else {
+				if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) {
+					retval = -1;
+					goto test_end;
+				}
+			}
+		}
+	}
+
+	/* Check if proper number of packets was send */
+	if (nb_pkts_sum < 4) {
+		retval = -1;
+		goto test_end;
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
+
+static int
+test_alb_receive_vlan_reply(void)
+{
+	struct ether_hdr *eth_pkt;
+	struct vlan_hdr *vlan_pkt;
+	struct arp_hdr *arp_pkt;
+
+	struct rte_mbuf *pkt;
+	struct rte_mbuf *pkts_sent[MAX_PKT_BURST];
+
+	int slave_idx, nb_pkts, pkt_idx;
+	int retval = 0;
+
+	struct ether_addr bond_mac, client_mac;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	/* Flush tx queue */
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+	}
+
+	ether_addr_copy(
+			rte_eth_devices[test_params->bonded_port_id].data->mac_addrs,
+			&bond_mac);
+
+	/*
+	 * Generating packet with double VLAN header and placing it in the rx queue.
+	 */
+	pkt = rte_pktmbuf_alloc(test_params->mbuf_pool);
+	memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN);
+	eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_VLAN, 0,
+			0);
+	vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1));
+	vlan_pkt->vlan_tci = rte_cpu_to_be_16(1);
+	vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	vlan_pkt = vlan_pkt+1;
+	vlan_pkt->vlan_tci = rte_cpu_to_be_16(2);
+	vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_ARP);
+	arp_pkt = (struct arp_hdr *)((char *)(vlan_pkt + 1));
+	initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host,
+			ARP_OP_REPLY);
+	virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt,
+			1);
+
+	rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST);
+	rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0);
+
+	/*
+	 * Checking if VLAN headers in generated ARP Update packet are correct.
+	 */
+	for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) {
+		nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue(
+				test_params->slave_port_ids[slave_idx], pkts_sent,
+				MAX_PKT_BURST);
+
+		for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
+			eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *);
+			vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1));
+			if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(1)) {
+				retval = -1;
+				goto test_end;
+			}
+			if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+				retval = -1;
+				goto test_end;
+			}
+			vlan_pkt = vlan_pkt+1;
+			if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(2)) {
+				retval = -1;
+				goto test_end;
+			}
+			if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_ARP)) {
+				retval = -1;
+				goto test_end;
+			}
+		}
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
+
+static int
+test_alb_ipv4_tx(void)
+{
+	int burst_size, retval, pkts_send;
+	struct rte_mbuf *pkt_burst[MAX_PKT_BURST];
+
+	retval = 0;
+
+	TEST_ASSERT_SUCCESS(
+			initialize_bonded_device_with_slaves(BONDING_MODE_ALB,
+					0, TEST_ALB_SLAVE_COUNT, 1),
+			"Failed to initialize_bonded_device_with_slaves.");
+
+	burst_size = 32;
+
+	/* Generate test bursts of packets to transmit */
+	if (generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0) != burst_size) {
+		retval = -1;
+		goto test_end;
+	}
+
+	/*
+	 * Checking if ipv4 traffic is transmitted via TLB policy.
+	 */
+	pkts_send = rte_eth_tx_burst(
+			test_params->bonded_port_id, 0, pkt_burst, burst_size);
+	if (pkts_send != burst_size) {
+		retval = -1;
+		goto test_end;
+	}
+
+test_end:
+	retval += remove_slaves_and_stop_bonded_device();
+	return retval;
+}
 
 static struct unit_test_suite link_bonding_test_suite  = {
 	.suite_name = "Link Bonding Unit Test Suite",
@@ -4593,6 +5000,10 @@ static struct unit_test_suite link_bonding_test_suite  = {
 		TEST_CASE(test_tlb_verify_mac_assignment),
 		TEST_CASE(test_tlb_verify_promiscuous_enable_disable),
 		TEST_CASE(test_tlb_verify_slave_link_status_change_failover),
+		TEST_CASE(test_alb_change_mac_in_reply_sent),
+		TEST_CASE(test_alb_reply_from_client),
+		TEST_CASE(test_alb_receive_vlan_reply),
+		TEST_CASE(test_alb_ipv4_tx),
 #ifdef RTE_MBUF_REFCNT
 		TEST_CASE(test_broadcast_tx_burst),
 		TEST_CASE(test_broadcast_tx_burst_slave_tx_fail),
diff --git a/app/test/test_pmd_perf.c b/app/test/test_pmd_perf.c
index bad9503..d6a4a45 100644
--- a/app/test/test_pmd_perf.c
+++ b/app/test/test_pmd_perf.c
@@ -235,8 +235,7 @@ init_traffic(struct rte_mempool *mp,
 
 	initialize_eth_header(&pkt_eth_hdr,
 		(struct ether_addr *)src_mac,
-		(struct ether_addr *)dst_mac, 1, 0, 0);
-	pkt_eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		(struct ether_addr *)dst_mac, ETHER_TYPE_IPv4, 0, 0);
 
 	pktlen = initialize_ipv4_header(&pkt_ipv4_hdr,
 					IPV4_ADDR(10, 0, 0, 1),
diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
index 9fac95d..cd9faf3 100644
--- a/app/test/virtual_pmd.c
+++ b/app/test/virtual_pmd.c
@@ -36,6 +36,7 @@
 #include <rte_malloc.h>
 #include <rte_memcpy.h>
 #include <rte_memory.h>
+#include <rte_ring.h>
 
 #include "virtual_pmd.h"
 
@@ -46,8 +47,8 @@ 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 rte_ring *rx_queue;
+	struct rte_ring *tx_queue;
 
 	int tx_burst_fail_count;
 };
@@ -74,8 +75,16 @@ virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev __rte_unused)
 }
 static void  virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused)
 {
+	struct rte_mbuf *pkt = NULL;
+	struct virtual_ethdev_private *prv = eth_dev->data->dev_private;
+
 	eth_dev->data->dev_link.link_status = 0;
 	eth_dev->data->dev_started = 0;
+	while (rte_ring_dequeue(prv->rx_queue, (void **)&pkt) != -ENOENT)
+		rte_pktmbuf_free(pkt);
+
+	while (rte_ring_dequeue(prv->tx_queue, (void **)&pkt) != -ENOENT)
+		rte_pktmbuf_free(pkt);
 }
 
 static void
@@ -214,8 +223,10 @@ static void
 virtual_ethdev_stats_reset(struct rte_eth_dev *dev)
 {
 	struct virtual_ethdev_private *dev_private = dev->data->dev_private;
+	struct rte_mbuf *pkt = NULL;
 
-	dev_private->rx_pkt_burst_len = 0;
+	while (rte_ring_dequeue(dev_private->tx_queue, (void **)&pkt) == -ENOBUFS)
+			rte_pktmbuf_free(pkt);
 
 	/* Reset internal statistics */
 	memset(&dev_private->eth_stats, 0, sizeof(dev_private->eth_stats));
@@ -318,29 +329,23 @@ virtual_ethdev_rx_burst_success(void *queue __rte_unused,
 	struct virtual_ethdev_queue *pq_map;
 	struct virtual_ethdev_private *dev_private;
 
-	int i;
+	int rx_count, 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) {
+	rx_count = rte_ring_dequeue_burst(dev_private->rx_queue, (void **) bufs,
+			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;
-			}
+	/* increments ipackets count */
+	dev_private->eth_stats.ipackets += rx_count;
 
-			dev_private->eth_stats.ipackets = dev_private->rx_pkt_burst_len;
-		}
-		/* reset private burst values */
-		dev_private->rx_pkt_burst_len = 0;
-	}
+	/* increments ibytes count */
+	for (i = 0; i < rx_count; i++)
+		dev_private->eth_stats.ibytes += rte_pktmbuf_pkt_len(bufs[i]);
 
-	return dev_private->eth_stats.ipackets;
+	return rx_count;
 }
 
 static uint16_t
@@ -359,26 +364,26 @@ virtual_ethdev_tx_burst_success(void *queue, struct rte_mbuf **bufs,
 
 	struct rte_eth_dev *vrtl_eth_dev;
 	struct virtual_ethdev_private *dev_private;
-	uint64_t obytes = 0;
+
 	int i;
 
-	for (i = 0; i < nb_pkts; i++)
-		obytes += rte_pktmbuf_pkt_len(bufs[i]);
 	vrtl_eth_dev = &rte_eth_devices[tx_q->port_id];
 	dev_private = vrtl_eth_dev->data->dev_private;
 
-	if (vrtl_eth_dev->data->dev_link.link_status) {
-		/* increment opacket count */
-		dev_private->eth_stats.opackets += nb_pkts;
-		dev_private->eth_stats.obytes += obytes;
-		/* free packets in burst */
-		for (i = 0; i < nb_pkts; i++)
-			rte_pktmbuf_free(bufs[i]);
+	if (!vrtl_eth_dev->data->dev_link.link_status)
+		nb_pkts = 0;
+	else
+		nb_pkts = rte_ring_enqueue_burst(dev_private->tx_queue, (void **)bufs,
+				nb_pkts);
 
-		return nb_pkts;
-	}
+	/* increment opacket count */
+	dev_private->eth_stats.opackets += nb_pkts;
 
-	return 0;
+	/* increment obytes count */
+	for (i = 0; i < nb_pkts; i++)
+		dev_private->eth_stats.obytes += rte_pktmbuf_pkt_len(bufs[i]);
+
+	return nb_pkts;
 }
 
 static uint16_t
@@ -476,23 +481,28 @@ virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
 	_rte_eth_dev_callback_process(vrtl_eth_dev, RTE_ETH_EVENT_INTR_LSC);
 }
 
-
-
-void
+int
 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];
+	struct virtual_ethdev_private *dev_private =
+			vrtl_eth_dev->data->dev_private;
 
-	int i;
-
-	dev_private = vrtl_eth_dev->data->dev_private;
+	return rte_ring_enqueue_burst(dev_private->rx_queue, (void **)pkt_burst,
+			burst_length);
+}
 
-	for (i = 0; i < burst_length; i++)
-		dev_private->rx_pkt_burst[i] = pkt_burst[i];
+int
+virtual_ethdev_get_mbufs_from_tx_queue(uint8_t port_id,
+		struct rte_mbuf **pkt_burst, int burst_length)
+{
+	struct virtual_ethdev_private *dev_private;
+	struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id];
 
-	dev_private->rx_pkt_burst_len = burst_length;
+	dev_private = vrtl_eth_dev->data->dev_private;
+	return rte_ring_dequeue_burst(dev_private->tx_queue, (void **)pkt_burst,
+		burst_length);
 }
 
 static uint8_t
@@ -510,7 +520,6 @@ get_number_of_sockets(void)
 	return ++sockets;
 }
 
-
 int
 virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 		uint8_t socket_id, uint8_t isr_support)
@@ -522,6 +531,7 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 	struct eth_dev_ops *dev_ops = NULL;
 	struct rte_pci_id *id_table = NULL;
 	struct virtual_ethdev_private *dev_private = NULL;
+	char name_buf[RTE_RING_NAMESIZE];
 
 
 	/* now do all data allocation - for eth_dev structure, dummy pci driver
@@ -555,6 +565,20 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 	if (dev_private == NULL)
 		goto err;
 
+	memset(dev_private, 0, sizeof(*dev_private));
+
+	snprintf(name_buf, sizeof(name_buf), "%s_rxQ", name);
+	dev_private->rx_queue = rte_ring_create(name_buf, MAX_PKT_BURST, socket_id,
+			0);
+	if (dev_private->rx_queue == NULL)
+		goto err;
+
+	snprintf(name_buf, sizeof(name_buf), "%s_txQ", name);
+	dev_private->tx_queue = rte_ring_create(name_buf, MAX_PKT_BURST, socket_id,
+			0);
+	if (dev_private->tx_queue == NULL)
+		goto err;
+
 	/* reserve an ethdev entry */
 	eth_dev = rte_eth_dev_allocate(name);
 	if (eth_dev == NULL)
@@ -594,7 +618,6 @@ virtual_ethdev_create(const char *name, struct ether_addr *mac_addr,
 	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;
diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h
index 2462853..de00188 100644
--- a/app/test/virtual_pmd.h
+++ b/app/test/virtual_pmd.h
@@ -54,10 +54,13 @@ void
 virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id,
 		uint8_t link_status);
 
-void
+int
 virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id,
 		struct rte_mbuf **pkts_burst, int burst_length);
 
+int
+virtual_ethdev_get_mbufs_from_tx_queue(uint8_t port_id,
+		struct rte_mbuf **pkt_burst, int burst_length);
 
 /** Control methods for the dev_ops functions pointer to control the behavior
  *  of the Virtual PMD */
-- 
1.7.9.5

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

* Re: [dpdk-dev] [PATCH v3 4/6] bond: add example application for link bonding mode 6
  2015-02-20 14:42     ` Thomas Monjalon
@ 2015-02-20 16:12       ` Jastrzebski, MichalX K
  0 siblings, 0 replies; 35+ messages in thread
From: Jastrzebski, MichalX K @ 2015-02-20 16:12 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Friday, February 20, 2015 3:43 PM
> To: Jastrzebski, MichalX K
> Cc: dev@dpdk.org; Butler, Siobhan A
> Subject: Re: [dpdk-dev] [PATCH v3 4/6] bond: add example application for
> link bonding mode 6
> 
> 2015-02-19 18:26, Michal Jastrzebski:
> > + *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
> 
> You should check the date.
> Is there some reviews of the copyright at Intel? It's quite common to see
> these dates starting and finishing too early.
> 
> > +#ifdef RTE_EXEC_ENV_BAREMETAL
> > +#define MAIN _main
> > +#else
> > +#define MAIN main
> > +#endif
> 
> No more bare metal support.

Thanks Thomas,
I sent a v4.

Best regards
Michal

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

* Re: [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB)
  2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
                     ` (5 preceding siblings ...)
  2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 6/6] bond: add unit tests for link bonding mode 6 Michal Jastrzebski
@ 2015-02-20 17:44   ` Declan Doherty
  2015-02-20 21:58     ` Thomas Monjalon
  2015-03-04  3:53     ` Jiajia, SunX
  6 siblings, 2 replies; 35+ messages in thread
From: Declan Doherty @ 2015-02-20 17:44 UTC (permalink / raw)
  To: Michal Jastrzebski, dev

On 20/02/15 16:09, Michal Jastrzebski wrote:
> v4 changes:
> - license year modified
> - aded license to rte_eth_bond_alb files
> - removed RTE_EXEC_ENV_BAREMETAL in #define
>
> v3 changes:
> - completed description for mode 5 unit tests patch
> - fixed errors required by checkpatch.pl
> - moved patch version changes from patches to cover-letter
>
> v2 changes:
> in mode 6 patch 2/6:
> - add VLAN support
> - fixed sending duplicated ARPupdates
> - fixed assigning slaves for next clients
> - fixed TLB mode
>
> in debug patch 3/6:
> - add IPv4 RX/TX information
> - add mode6_debug(..) function
>
> in the example application patch 4/6:
> - remove count parameter from send command
> - fixed quit command to use cmdline_quit(cl)
> - add echo function - all IPv4 packets will be retransmitted. Bonding
> 	driver will use TLB policy - this will show how TX works in mode 6
> - remove unused structures rx_conf_default and tx_conf_default
> - add VLAN support
> - remove unnecessary comments
> - nodify show command in term of printing DEBUG informations
>
> This patchset add support for link bonding mode 6.
> Additionally it changes an arp_header structure definition.
> Also a basic example is introduced. Using this example,
> Bonding will configure each client ARP table,
> that packets from each client will be received on different slave,
> mode 6 uses round-robin policy to assign slave to client IP address.
>
> Daniel Mrzyglod (1):
>    bond: modify TLB unit tests
>
> Maciej Gajdzica (3):
>    net: changed arp_hdr struct declaration
>    bond: add link bonding mode 6 implementation
>    bond: add unit tests for link bonding mode 6.
>
> Michal Jastrzebski (2):
>    bond: add debug info for mode 6 link bonding
>    bond: add example application for link bonding mode 6
>
>   app/test-pmd/icmpecho.c                    |   27 +-
>   app/test/packet_burst_generator.c          |   41 +-
>   app/test/packet_burst_generator.h          |   11 +-
>   app/test/test_link_bonding.c               |  450 +++++++++++++++-
>   app/test/test_pmd_perf.c                   |    3 +-
>   app/test/virtual_pmd.c                     |  109 ++--
>   app/test/virtual_pmd.h                     |    5 +-
>   config/common_linuxapp                     |    3 +-
>   examples/bond/Makefile                     |   57 ++
>   examples/bond/main.c                       |  796 ++++++++++++++++++++++++++++
>   examples/bond/main.h                       |   39 ++
>   lib/librte_net/rte_arp.h                   |   13 +-
>   lib/librte_pmd_bond/Makefile               |    1 +
>   lib/librte_pmd_bond/rte_eth_bond.h         |   11 +-
>   lib/librte_pmd_bond/rte_eth_bond_alb.c     |  289 ++++++++++
>   lib/librte_pmd_bond/rte_eth_bond_alb.h     |  142 +++++
>   lib/librte_pmd_bond/rte_eth_bond_api.c     |   28 +-
>   lib/librte_pmd_bond/rte_eth_bond_args.c    |    3 +-
>   lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  460 ++++++++++++++--
>   lib/librte_pmd_bond/rte_eth_bond_private.h |   12 +
>   20 files changed, 2354 insertions(+), 146 deletions(-)
>   create mode 100644 examples/bond/Makefile
>   create mode 100644 examples/bond/main.c
>   create mode 100644 examples/bond/main.h
>   create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c
>   create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h
>

Series Acked-by: Declan Doherty <declan.doherty@intel.com>

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

* Re: [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB)
  2015-02-20 17:44   ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Declan Doherty
@ 2015-02-20 21:58     ` Thomas Monjalon
  2015-03-04  3:53     ` Jiajia, SunX
  1 sibling, 0 replies; 35+ messages in thread
From: Thomas Monjalon @ 2015-02-20 21:58 UTC (permalink / raw)
  To: Michal Jastrzebski; +Cc: dev

> > v4 changes:
> > - license year modified
> > - aded license to rte_eth_bond_alb files
> > - removed RTE_EXEC_ENV_BAREMETAL in #define
> >
> > v3 changes:
> > - completed description for mode 5 unit tests patch
> > - fixed errors required by checkpatch.pl
> > - moved patch version changes from patches to cover-letter
> >
> > v2 changes:
> > in mode 6 patch 2/6:
> > - add VLAN support
> > - fixed sending duplicated ARPupdates
> > - fixed assigning slaves for next clients
> > - fixed TLB mode
> >
> > in debug patch 3/6:
> > - add IPv4 RX/TX information
> > - add mode6_debug(..) function
> >
> > in the example application patch 4/6:
> > - remove count parameter from send command
> > - fixed quit command to use cmdline_quit(cl)
> > - add echo function - all IPv4 packets will be retransmitted. Bonding
> > 	driver will use TLB policy - this will show how TX works in mode 6
> > - remove unused structures rx_conf_default and tx_conf_default
> > - add VLAN support
> > - remove unnecessary comments
> > - nodify show command in term of printing DEBUG informations
> >
> > This patchset add support for link bonding mode 6.
> > Additionally it changes an arp_header structure definition.
> > Also a basic example is introduced. Using this example,
> > Bonding will configure each client ARP table,
> > that packets from each client will be received on different slave,
> > mode 6 uses round-robin policy to assign slave to client IP address.
> >
> > Daniel Mrzyglod (1):
> >    bond: modify TLB unit tests
> >
> > Maciej Gajdzica (3):
> >    net: changed arp_hdr struct declaration
> >    bond: add link bonding mode 6 implementation
> >    bond: add unit tests for link bonding mode 6.
> >
> > Michal Jastrzebski (2):
> >    bond: add debug info for mode 6 link bonding
> >    bond: add example application for link bonding mode 6
> 
> Series Acked-by: Declan Doherty <declan.doherty@intel.com>

Applied, thanks

I've added the new example in MAINTAINERS file, so I assume Declan maintain it.

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

* Re: [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB)
  2015-02-20 17:44   ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Declan Doherty
  2015-02-20 21:58     ` Thomas Monjalon
@ 2015-03-04  3:53     ` Jiajia, SunX
  1 sibling, 0 replies; 35+ messages in thread
From: Jiajia, SunX @ 2015-03-04  3:53 UTC (permalink / raw)
  To: Doherty, Declan, Jastrzebski, MichalX K, dev

Tested-by: Jiajia, SunX <sunx.jiajia@intel.com>

- Tested Commit: 8bfc4e3c4cb922d9c7e6b8934fdaffba268c7ed2
- OS: Fedora20 3.11.10-301.fc20.x86_64
- GCC: gcc version 4.8.3
- CPU: Intel(R) Xeon(R) CPU E5-2680 v2 @ 2.80GHz
- NIC: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection [8086:10fb]
- Target x86_64-native-linuxapp-gcc 
- Total 3 cases, 3 passed, 0 failed


* Connections ports between tester/ixia and switch and DUT
  - TESTER(Or IXIA)-------SWITCH
  -                       SWITCH---------DUT
  - TESTER(Or IXIA)----------------------DUT
  - portA------------------switch
  -                        switch----------port0
  -                        switch----------port1
  -                        switch----------port2
  - portB----------------------------------port3
* Connections ports between tester/ixia and switch and DUT
  - TESTER(Or IXIA)-------SWITCH
  -                       SWITCH---------DUT
  - TESTER(Or IXIA)----------------------DUT
  - portA-----------------switch
  - portB-----------------switch
  - portC-----------------switch
  -                       switch----------port0
  -                       switch----------port1
  -                       switch----------port2
 
Test Setup#1 for Functional test
================================

Tester has 4 ports(portA--portD), and DUT has 4 ports(port0--port3), then connect portA to port0, portB to port1, portC to port2, portD to port3. 


Test Setup#2 for Functional test
================================

Tester has 2 ports(portA--portB), DUT has 4 ports(port0--port3), and a switch that supports IEEE 802.3ad Dynamic link aggregation, then connect port0-port2 to the switch for dynamic link aggregation, connect portA to aggregated interface on the switch, connect portB to port3. 

Test Setup#3 for Functional test
================================

Tester has 3 ports(portA--portC), DUT has 3 ports(port0--port2), and a switch, then connect port0-port2 to three ports on the switch, connect portA - portB to the other three ports on the switch. 

Test App
===============================

Use testpmd to test the mode 0, 1, 2, 3, 4, 5, use bond_app to test the mode 6. If test the mode 6, Set the tester port address to 
7.0.0.1, 7.0.0.2, 7.0.0.3. And it will be better to turn on the debug switch on the config:
CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n - deeper debug, if you want all arp and ipv4 packets be printed 
CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n - don't print packets information, just collects statistics from clients, you can print these statistics with show command.


Test Case1: Mode 6(Adaptive load balance) Basic test
=============================================================================

Verify basic commands of bond_app work well.

Use Setup#3

Now bond_app has commands of send, start, stop, show, help, quit
help:

      execute command 'help' in the bond_app, verify it will print all commands help info.

send:

	  make sure that bond_app has been started, execute command 'send 7.0.0.1' on server, use 
	  tcpdump to listen client1 port , verify the port will receive ARP requests.

start:

      step1:
            execute command 'stop' in the bond_app, then execute 'arping -c 1 -I device 7.0.0.10' on the client1,
            verify bond_app will not receive and reply the client1 ARP request.
      Step2:
            Execute command 'start' in the bond_app, then execute 'arping -c 1 -I device 7.0.0.10' on the client1,
            Verify bond_app will receive and reply the client1 ARP request.

stop:

     continue the test of  command 'start', rerun step1.

show:

     execute command 'show' in the bond_app, verify it will print  some bond info: ex. active slaves etc.

quit:

     execute command 'quit' in the bond_app, verify it will terminate all threads and quit.
                
Verify bond_app can check the state of slaves, and do some actions.

Use Setup#1

Start bond_app.

Step1:

      Send 1 ARP request packet to bond0 from client1, verify it will receive and reply it on one slave.

Step2:

	  Bring the port of client1 link down,  verify bond0 will detect the change of slaves, by the command
      'show' to check the state of bond0, verify there are just two slaves.

Step3:

      Send 1 ARP request packet to bond0 on bond1 from client1, verify it will receive nothing.


Test Case2: Mode 6(Adaptive load balance) RX test of mode6
=============================================================================

Verify bond device can receive load balancing for IPV4 traffic.

Use Setup#3

Step1:

      Send ARP request packet (no VLAN header) to bond0 from each client, verify bond0 will choose 
      different slave to reply the request by the policy of round-robin.
      You can use the command 'arping -c 1 -I device 7.0.0.10' to server on each client. The device will
      need you to change it to the interface name of your client.

Step2:

      Send ARP request packet tagged with VLAN header to bond0 from each client, verify bond0 will
      choose different slave to reply the request by the policy of round-robin. The VLAN header will not
      affect the policy of choosing slave to reply the request.
      You can use the scapy to send these packet as below:
                                
      >>> eth = Ether(src='choose-client-port-mac')
      >>> arp = ARP(hwsrc='choose-client-port-mac', psrc='choose-port-ip', pdst='7.0.0.10')
      >>> dot1q = Dot1Q(vlan=1)
      >>> packet = eth/dot1q/arp
      >>> recv = srp1(packet, iface='choose-port-interface-name', timeout=2)

Test Case3: Mode 6(Adaptive load balance) TX test of mode6
=============================================================================

Verify bond device can transmit load balance.

Use Setup#3

Use scapy to send 1000 IP packets to bond0, verify slave0, slave1 and slave2 will transmit packets like this:
average = packet_num / slave_num; average*0.9 < slave_transmit_num < 1.1*average; so each slave
will receive packets between 300 and 367.

You can use scapy to send packets as below:

    >>> eth = Ether(src='choose-client-port-mac')
    >>> ip = IP(len=66, dst='7.0.0.10')
    >>> packet = eth/ip
    >>> sendp(packet, iface='choose-port-interface-name', count=1000)



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Declan Doherty
> Sent: Saturday, February 21, 2015 1:45 AM
> To: Jastrzebski, MichalX K; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB)
> 
> On 20/02/15 16:09, Michal Jastrzebski wrote:
> > v4 changes:
> > - license year modified
> > - aded license to rte_eth_bond_alb files
> > - removed RTE_EXEC_ENV_BAREMETAL in #define
> >
> > v3 changes:
> > - completed description for mode 5 unit tests patch
> > - fixed errors required by checkpatch.pl
> > - moved patch version changes from patches to cover-letter
> >
> > v2 changes:
> > in mode 6 patch 2/6:
> > - add VLAN support
> > - fixed sending duplicated ARPupdates
> > - fixed assigning slaves for next clients
> > - fixed TLB mode
> >
> > in debug patch 3/6:
> > - add IPv4 RX/TX information
> > - add mode6_debug(..) function
> >
> > in the example application patch 4/6:
> > - remove count parameter from send command
> > - fixed quit command to use cmdline_quit(cl)
> > - add echo function - all IPv4 packets will be retransmitted. Bonding
> > 	driver will use TLB policy - this will show how TX works in mode
> 6
> > - remove unused structures rx_conf_default and tx_conf_default
> > - add VLAN support
> > - remove unnecessary comments
> > - nodify show command in term of printing DEBUG informations
> >
> > This patchset add support for link bonding mode 6.
> > Additionally it changes an arp_header structure definition.
> > Also a basic example is introduced. Using this example,
> > Bonding will configure each client ARP table,
> > that packets from each client will be received on different slave,
> > mode 6 uses round-robin policy to assign slave to client IP address.
> >
> > Daniel Mrzyglod (1):
> >    bond: modify TLB unit tests
> >
> > Maciej Gajdzica (3):
> >    net: changed arp_hdr struct declaration
> >    bond: add link bonding mode 6 implementation
> >    bond: add unit tests for link bonding mode 6.
> >
> > Michal Jastrzebski (2):
> >    bond: add debug info for mode 6 link bonding
> >    bond: add example application for link bonding mode 6
> >
> >   app/test-pmd/icmpecho.c                    |   27 +-
> >   app/test/packet_burst_generator.c          |   41 +-
> >   app/test/packet_burst_generator.h          |   11 +-
> >   app/test/test_link_bonding.c               |  450 +++++++++++++++-
> >   app/test/test_pmd_perf.c                   |    3 +-
> >   app/test/virtual_pmd.c                     |  109 ++--
> >   app/test/virtual_pmd.h                     |    5 +-
> >   config/common_linuxapp                     |    3 +-
> >   examples/bond/Makefile                     |   57 ++
> >   examples/bond/main.c                       |  796
> ++++++++++++++++++++++++++++
> >   examples/bond/main.h                       |   39 ++
> >   lib/librte_net/rte_arp.h                   |   13 +-
> >   lib/librte_pmd_bond/Makefile               |    1 +
> >   lib/librte_pmd_bond/rte_eth_bond.h         |   11 +-
> >   lib/librte_pmd_bond/rte_eth_bond_alb.c     |  289 ++++++++++
> >   lib/librte_pmd_bond/rte_eth_bond_alb.h     |  142 +++++
> >   lib/librte_pmd_bond/rte_eth_bond_api.c     |   28 +-
> >   lib/librte_pmd_bond/rte_eth_bond_args.c    |    3 +-
> >   lib/librte_pmd_bond/rte_eth_bond_pmd.c     |  460 ++++++++++++++--
> >   lib/librte_pmd_bond/rte_eth_bond_private.h |   12 +
> >   20 files changed, 2354 insertions(+), 146 deletions(-)
> >   create mode 100644 examples/bond/Makefile
> >   create mode 100644 examples/bond/main.c
> >   create mode 100644 examples/bond/main.h
> >   create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.c
> >   create mode 100644 lib/librte_pmd_bond/rte_eth_bond_alb.h
> >
> 
> Series Acked-by: Declan Doherty <declan.doherty@intel.com>

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

end of thread, other threads:[~2015-03-04  3:54 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-13 15:16 [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 2/6] bond: add link bonding mode 6 implementation Michal Jastrzebski
2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 3/6] bond: add debug info for mode 6 link bonding Michal Jastrzebski
2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 5/6] bond: modify TLB unit tests Michal Jastrzebski
2015-02-13 15:16 ` [dpdk-dev] [PATCH v2 6/6] bond: add unit tests for link bonding mode 6 Michal Jastrzebski
2015-02-13 16:12 ` [dpdk-dev] [PATCH v2 0/6] Link Bonding mode 6 support (ALB) Declan Doherty
2015-02-18 19:10   ` Thomas Monjalon
2015-02-19  9:18     ` Jastrzebski, MichalX K
2015-02-19  9:39       ` Thomas Monjalon
2015-02-19 10:14         ` Jastrzebski, MichalX K
2015-02-19 10:27           ` Thomas Monjalon
2015-02-19 17:26 ` [dpdk-dev] [PATCH v3 " Michal Jastrzebski
2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
2015-02-20 14:30     ` Thomas Monjalon
2015-02-20 14:54       ` Gajdzica, MaciejX T
2015-02-20 15:22         ` Thomas Monjalon
2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 2/6] bond: add link bonding mode 6 implementation Michal Jastrzebski
2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 3/6] bond: add debug info for mode 6 link bonding Michal Jastrzebski
2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
2015-02-20 14:42     ` Thomas Monjalon
2015-02-20 16:12       ` Jastrzebski, MichalX K
2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 5/6] bond: modify TLB unit tests Michal Jastrzebski
2015-02-19 17:26   ` [dpdk-dev] [PATCH v3 6/6] bond: add unit tests for link bonding mode 6 Michal Jastrzebski
2015-02-20 16:09 ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Michal Jastrzebski
2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 1/6] net: changed arp_hdr struct declaration Michal Jastrzebski
2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 2/6] bond: add link bonding mode 6 implementation Michal Jastrzebski
2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 3/6] bond: add debug info for mode 6 link bonding Michal Jastrzebski
2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 4/6] bond: add example application for link bonding mode 6 Michal Jastrzebski
2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 5/6] bond: modify TLB unit tests Michal Jastrzebski
2015-02-20 16:09   ` [dpdk-dev] [PATCH v4 6/6] bond: add unit tests for link bonding mode 6 Michal Jastrzebski
2015-02-20 17:44   ` [dpdk-dev] [PATCH v4 0/6] Link Bonding mode 6 support (ALB) Declan Doherty
2015-02-20 21:58     ` Thomas Monjalon
2015-03-04  3:53     ` Jiajia, SunX

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).