* [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests
@ 2014-12-12 9:14 Michal Jastrzebski
2014-12-12 9:14 ` [dpdk-dev] [PATCH 1/3] bond change warning Michal Jastrzebski
` (3 more replies)
0 siblings, 4 replies; 30+ messages in thread
From: Michal Jastrzebski @ 2014-12-12 9:14 UTC (permalink / raw)
To: dev; +Cc: tomaszx.kulasek
These patches add unit tests for mode 4. They also changes ring pmd
to behave more like ordinary pmd device.
Pawel Wodkowski (3):
bond-change-warning
PMD-ring-MAC-management-fix-initialization-link-up-d
unit-tests-add-mode-4-unit-test
app/test/Makefile | 1 +
app/test/test.h | 111 ++-
app/test/test_link_bonding.c | 2 +-
app/test/test_link_bonding_mode4.c | 1412 ++++++++++++++++++++++++++++++++
lib/librte_pmd_bond/rte_eth_bond_pmd.c | 4 +-
lib/librte_pmd_ring/rte_eth_ring.c | 62 +-
6 files changed, 1539 insertions(+), 53 deletions(-)
create mode 100644 app/test/test_link_bonding_mode4.c
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH 1/3] bond change warning
2014-12-12 9:14 [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests Michal Jastrzebski
@ 2014-12-12 9:14 ` Michal Jastrzebski
2015-02-18 18:06 ` Thomas Monjalon
2014-12-12 9:14 ` [dpdk-dev] [PATCH 2/3] PMD ring MAC management, fix initialization, link up/down Michal Jastrzebski
` (2 subsequent siblings)
3 siblings, 1 reply; 30+ messages in thread
From: Michal Jastrzebski @ 2014-12-12 9:14 UTC (permalink / raw)
To: dev; +Cc: tomaszx.kulasek
Remove function name from warning.
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
lib/librte_pmd_bond/rte_eth_bond_pmd.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/librte_pmd_bond/rte_eth_bond_pmd.c b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
index 539baa4..9169040 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_pmd.c
+++ b/lib/librte_pmd_bond/rte_eth_bond_pmd.c
@@ -891,9 +891,9 @@ bond_ethdev_mode_set(struct rte_eth_dev *eth_dev, int mode)
eth_dev->rx_pkt_burst = bond_ethdev_rx_burst_8023ad;
eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_8023ad;
- RTE_BOND_LOG(WARNING,
+ RTE_LOG(WARNING, PMD,
"Using mode 4, it is necessary to do TX burst and RX burst "
- "at least every 100ms.");
+ "at least every 100ms.\n");
break;
case BONDING_MODE_ADAPTIVE_TRANSMIT_LOAD_BALANCING:
eth_dev->tx_pkt_burst = bond_ethdev_tx_burst_tlb;
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH 2/3] PMD ring MAC management, fix initialization, link up/down
2014-12-12 9:14 [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests Michal Jastrzebski
2014-12-12 9:14 ` [dpdk-dev] [PATCH 1/3] bond change warning Michal Jastrzebski
@ 2014-12-12 9:14 ` Michal Jastrzebski
2015-01-15 10:53 ` Thomas Monjalon
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 0/3] " Tomasz Kulasek
2014-12-12 9:14 ` [dpdk-dev] [PATCH 3/3] unit tests add mode 4 unit test Michal Jastrzebski
2014-12-12 15:27 ` [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests Doherty, Declan
3 siblings, 2 replies; 30+ messages in thread
From: Michal Jastrzebski @ 2014-12-12 9:14 UTC (permalink / raw)
To: dev; +Cc: tomaszx.kulasek
* add MAC management per device
* fix initialization procedure
* add link up/down functions
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
lib/librte_pmd_ring/rte_eth_ring.c | 62 +++++++++++++++++++++++++++++++++---
1 file changed, 57 insertions(+), 5 deletions(-)
diff --git a/lib/librte_pmd_ring/rte_eth_ring.c b/lib/librte_pmd_ring/rte_eth_ring.c
index 4f1b6ed..b6047cc 100644
--- a/lib/librte_pmd_ring/rte_eth_ring.c
+++ b/lib/librte_pmd_ring/rte_eth_ring.c
@@ -44,6 +44,8 @@
#define ETH_RING_ACTION_CREATE "CREATE"
#define ETH_RING_ACTION_ATTACH "ATTACH"
+static const char *ring_ethdev_driver_name = "Ring PMD";
+
static const char *valid_arguments[] = {
ETH_RING_NUMA_NODE_ACTION_ARG,
NULL
@@ -62,10 +64,11 @@ struct pmd_internals {
struct ring_queue rx_ring_queues[RTE_PMD_RING_MAX_RX_RINGS];
struct ring_queue tx_ring_queues[RTE_PMD_RING_MAX_TX_RINGS];
+
+ struct ether_addr address;
};
-static struct ether_addr eth_addr = { .addr_bytes = {0} };
static const char *drivername = "Rings PMD";
static struct rte_eth_link pmd_link = {
.link_speed = 10000,
@@ -121,6 +124,20 @@ eth_dev_stop(struct rte_eth_dev *dev)
}
static int
+eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = 0;
+ return 0;
+}
+
+static int
+eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = 1;
+ return 0;
+}
+
+static int
eth_rx_queue_setup(struct rte_eth_dev *dev,uint16_t rx_queue_id,
uint16_t nb_rx_desc __rte_unused,
unsigned int socket_id __rte_unused,
@@ -199,6 +216,20 @@ eth_stats_reset(struct rte_eth_dev *dev)
}
static void
+eth_mac_addr_remove(struct rte_eth_dev *dev __rte_unused,
+ uint32_t index __rte_unused)
+{
+}
+
+static void
+eth_mac_addr_add(struct rte_eth_dev *dev __rte_unused,
+ struct ether_addr *mac_addr __rte_unused,
+ uint32_t index __rte_unused,
+ uint32_t vmdq __rte_unused)
+{
+}
+
+static void
eth_queue_release(void *q __rte_unused) { ; }
static int
eth_link_update(struct rte_eth_dev *dev __rte_unused,
@@ -207,6 +238,8 @@ eth_link_update(struct rte_eth_dev *dev __rte_unused,
static struct eth_dev_ops ops = {
.dev_start = eth_dev_start,
.dev_stop = eth_dev_stop,
+ .dev_set_link_up = eth_dev_set_link_up,
+ .dev_set_link_down = eth_dev_set_link_down,
.dev_configure = eth_dev_configure,
.dev_infos_get = eth_dev_info,
.rx_queue_setup = eth_rx_queue_setup,
@@ -216,6 +249,8 @@ static struct eth_dev_ops ops = {
.link_update = eth_link_update,
.stats_get = eth_stats_get,
.stats_reset = eth_stats_reset,
+ .mac_addr_remove = eth_mac_addr_remove,
+ .mac_addr_add = eth_mac_addr_add,
};
int
@@ -229,6 +264,9 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
struct rte_pci_device *pci_dev = NULL;
struct pmd_internals *internals = NULL;
struct rte_eth_dev *eth_dev = NULL;
+ struct eth_driver *eth_drv = NULL;
+ struct rte_pci_id *id_table = NULL;
+
unsigned i;
/* do some parameter checking */
@@ -251,6 +289,10 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
if (pci_dev == NULL)
goto error;
+ id_table = rte_zmalloc_socket(name, sizeof(*id_table), 0, numa_node);
+ if (id_table == NULL)
+ goto error;
+
internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
if (internals == NULL)
goto error;
@@ -260,6 +302,10 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
if (eth_dev == NULL)
goto error;
+ eth_drv = rte_zmalloc_socket(name, sizeof(*eth_drv), 0, numa_node);
+ if (eth_drv == NULL)
+ goto error;
+
/* now put it all together
* - store queue data in internals,
* - store numa_node info in pci_driver
@@ -278,18 +324,24 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
internals->tx_ring_queues[i].rng = tx_queues[i];
}
+ eth_drv->pci_drv.name = ring_ethdev_driver_name;
+ eth_drv->pci_drv.id_table = id_table;
+
pci_dev->numa_node = numa_node;
+ pci_dev->driver = ð_drv->pci_drv;
data->dev_private = internals;
data->port_id = eth_dev->data->port_id;
data->nb_rx_queues = (uint16_t)nb_rx_queues;
data->nb_tx_queues = (uint16_t)nb_tx_queues;
data->dev_link = pmd_link;
- data->mac_addrs = ð_addr;
+ data->mac_addrs = &internals->address;
- eth_dev ->data = data;
- eth_dev ->dev_ops = &ops;
- eth_dev ->pci_dev = pci_dev;
+ eth_dev->data = data;
+ eth_dev->driver = eth_drv;
+ eth_dev->dev_ops = &ops;
+ eth_dev->pci_dev = pci_dev;
+ TAILQ_INIT(&(eth_dev->callbacks));
/* finally assign rx and tx ops */
eth_dev->rx_pkt_burst = eth_ring_rx;
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH 3/3] unit tests add mode 4 unit test
2014-12-12 9:14 [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests Michal Jastrzebski
2014-12-12 9:14 ` [dpdk-dev] [PATCH 1/3] bond change warning Michal Jastrzebski
2014-12-12 9:14 ` [dpdk-dev] [PATCH 2/3] PMD ring MAC management, fix initialization, link up/down Michal Jastrzebski
@ 2014-12-12 9:14 ` Michal Jastrzebski
2015-01-15 10:55 ` Thomas Monjalon
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 0/2] " Tomasz Kulasek
2014-12-12 15:27 ` [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests Doherty, Declan
3 siblings, 2 replies; 30+ messages in thread
From: Michal Jastrzebski @ 2014-12-12 9:14 UTC (permalink / raw)
To: dev; +Cc: tomaszx.kulasek
This patch adds unit tests for mode 4. It is split into separate
file to avoid problems with other modes that does not need to
look into packets payload.
This patch includes also a modification of maximum number of ports
used in their tests for bonding modes 0-3 from 16 to 6.
Additionally some typos fix is included.
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
app/test/Makefile | 1 +
app/test/test.h | 111 +--
app/test/test_link_bonding.c | 2 +-
app/test/test_link_bonding_mode4.c | 1412 ++++++++++++++++++++++++++++++++++++
4 files changed, 1480 insertions(+), 46 deletions(-)
create mode 100644 app/test/test_link_bonding_mode4.c
diff --git a/app/test/Makefile b/app/test/Makefile
index 4311f96..ee0e95a 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -129,6 +129,7 @@ SRCS-y += virtual_pmd.c
SRCS-y += packet_burst_generator.c
SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding_mode4.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring.c
SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c
diff --git a/app/test/test.h b/app/test/test.h
index 72e67b9..53ef11d 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -36,62 +36,80 @@
#include <sys/queue.h>
-#define TEST_ASSERT(cond, msg, ...) do { \
- if (!(cond)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_SUCCESS (0)
+#define TEST_FAILED (-1)
+
+/* Before including test.h file you can define
+ * TEST_TRACE_FAILURE(_file, _line, _func) macro to better trace/debug test
+ * failures. Mostly useful in test development phase. */
+#ifndef TEST_TRACE_FAILURE
+# define TEST_TRACE_FAILURE(_file, _line, _func)
+#endif
+
+#define TEST_ASSERT(cond, msg, ...) do { \
+ if (!(cond)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_EQUAL(a, b, msg, ...) { \
- if (!(a == b)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_EQUAL(a, b, msg, ...) do { \
+ if (!(a == b)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_NOT_EQUAL(a, b, msg, ...) do { \
- if (!(a != b)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NOT_EQUAL(a, b, msg, ...) do { \
+ if (!(a != b)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \
- if (!(val == 0)) { \
- printf("TestCase %s() line %d failed (err %d): " \
- msg "\n", __func__, __LINE__, val, \
- ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \
+ typeof(val) _val = (val); \
+ if (!(_val == 0)) { \
+ printf("TestCase %s() line %d failed (err %d): " \
+ msg "\n", __func__, __LINE__, _val, \
+ ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_FAIL(val, msg, ...) do { \
- if (!(val != 0)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_FAIL(val, msg, ...) do { \
+ if (!(val != 0)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_NULL(val, msg, ...) do { \
- if (!(val == NULL)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NULL(val, msg, ...) do { \
+ if (!(val == NULL)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \
- if (!(val != NULL)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \
+ if (!(val != NULL)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
struct unit_test_case {
@@ -104,8 +122,11 @@ struct unit_test_case {
#define TEST_CASE(fn) { NULL, NULL, fn, #fn " succeeded", #fn " failed"}
-#define TEST_CASE_ST(setup, teardown, testcase) \
- { setup, teardown, testcase, #testcase " succeeded", \
+#define TEST_CASE_NAMED(name, fn) { NULL, NULL, fn, name " succeeded", \
+ name " failed"}
+
+#define TEST_CASE_ST(setup, teardown, testcase) \
+ { setup, teardown, testcase, #testcase " succeeded", \
#testcase " failed "}
#define TEST_CASES_END() { NULL, NULL, NULL, NULL, NULL }
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index f62c490..40490da 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -57,7 +57,7 @@
#include "test.h"
-#define TEST_MAX_NUMBER_OF_PORTS (16)
+#define TEST_MAX_NUMBER_OF_PORTS (6)
#define RX_RING_SIZE 128
#define RX_FREE_THRESH 32
diff --git a/app/test/test_link_bonding_mode4.c b/app/test/test_link_bonding_mode4.c
new file mode 100644
index 0000000..f8d0955
--- /dev/null
+++ b/app/test/test_link_bonding_mode4.c
@@ -0,0 +1,1412 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <rte_cycles.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_memory.h>
+
+#include <rte_string_fns.h>
+
+#include <rte_eth_ring.h>
+#include <rte_errno.h>
+#include <rte_eth_bond.h>
+#include <rte_eth_bond_8023ad.h>
+
+#include "packet_burst_generator.h"
+
+#include "test.h"
+
+#define SLAVE_COUNT (4)
+
+#define RX_RING_SIZE 128
+#define TX_RING_SIZE 512
+
+#define MBUF_PAYLOAD_SIZE (2048)
+#define MBUF_SIZE (MBUF_PAYLOAD_SIZE + sizeof(struct rte_mbuf) + \
+ RTE_PKTMBUF_HEADROOM)
+#define MBUF_CACHE_SIZE (250)
+#define BURST_SIZE (32)
+
+#define DEFAULT_MBUF_DATA_SIZE (2048)
+#define TEST_RX_DESC_MAX (2048)
+#define TEST_TX_DESC_MAX (2048)
+#define MAX_PKT_BURST (32)
+#define DEF_PKT_BURST (16)
+
+#define BONDED_DEV_NAME ("unit_test_mode4_bond_dev")
+
+#define SLAVE_DEV_NAME_FMT ("unit_test_mode4_slave_%d")
+#define SLAVE_RX_QUEUE_FMT ("unit_test_mode4_slave_%d_rx")
+#define SLAVE_TX_QUEUE_FMT ("unit_test_mode4_slave_%d_tx")
+
+#define INVALID_SOCKET_ID (-1)
+#define INVALID_PORT_ID (0xFF)
+#define INVALID_BONDING_MODE (-1)
+
+static const struct ether_addr slave_mac_default = {
+ { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 }
+};
+
+static const struct ether_addr parnter_mac_default = {
+ { 0x22, 0xBB, 0xFF, 0xBB, 0x00, 0x00 }
+};
+
+static const struct ether_addr parnter_system = {
+ { 0x33, 0xFF, 0xBB, 0xFF, 0x00, 0x00 }
+};
+
+static const struct ether_addr slow_protocol_mac_addr = {
+ { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 }
+};
+
+struct slave_conf {
+ struct rte_ring *rx_queue;
+ struct rte_ring *tx_queue;
+ uint8_t port_id;
+ uint8_t bonded : 1;
+
+ uint8_t lacp_parnter_state;
+};
+
+struct ether_vlan_hdr {
+ struct ether_hdr pkt_eth_hdr;
+ struct vlan_hdr vlan_hdr;
+};
+
+struct link_bonding_unittest_params {
+ uint8_t bonded_port_id;
+ struct slave_conf slave_ports[SLAVE_COUNT];
+
+ struct rte_mempool *mbuf_pool;
+};
+
+#define TEST_DEFAULT_SLAVE_COUNT RTE_DIM(test_params.slave_ports)
+#define TEST_RX_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_TX_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_MARKER_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_EXPIRED_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_PROMISC_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+
+static struct link_bonding_unittest_params test_params = {
+ .bonded_port_id = INVALID_PORT_ID,
+ .slave_ports = { [0 ... SLAVE_COUNT - 1] = { .port_id = INVALID_PORT_ID} },
+
+ .mbuf_pool = NULL,
+};
+
+static struct rte_eth_conf default_pmd_conf = {
+ .rxmode = {
+ .mq_mode = ETH_MQ_RX_NONE,
+ .max_rx_pkt_len = ETHER_MAX_LEN,
+ .split_hdr_size = 0,
+ .header_split = 0, /**< Header Split disabled */
+ .hw_ip_checksum = 0, /**< IP checksum offload enabled */
+ .hw_vlan_filter = 0, /**< VLAN filtering disabled */
+ .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /**< CRC stripped by hardware */
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+ .lpbk_mode = 0,
+};
+
+#define FOR_EACH(_i, _item, _array, _size) \
+ for (_i = 0, _item = &_array[0]; _i < _size && (_item = &_array[_i]); _i++)
+
+/* Macro for iterating over every port that can be used as a slave
+ * in this test.
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ */
+#define FOR_EACH_PORT(_i, _port) \
+ FOR_EACH(_i, _port, test_params.slave_ports, \
+ RTE_DIM(test_params.slave_ports))
+
+/* Macro for iterating over every port that can be used as a slave
+ * in this test and satisfy given condition.
+ *
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ * _condition condition that need to be checked
+ */
+#define FOR_EACH_PORT_IF(_i, _port, _condition) FOR_EACH_PORT((_i), (_port)) \
+ if (!!(_condition))
+
+/* Macro for iterating over every port that is currently a slave of a bonded
+ * device.
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ * */
+#define FOR_EACH_SLAVE(_i, _slave) \
+ FOR_EACH_PORT_IF(_i, _slave, (_slave)->bonded != 0)
+
+/*
+ * Returns packets from slaves TX queue.
+ * slave slave port
+ * buffer for packets
+ * size size of buffer
+ * return number of packets or negative error number
+ */
+static int
+slave_get_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_ring_dequeue_burst(slave->tx_queue, (void **)buf, size);
+}
+
+/*
+ * Injects given packets into slaves RX queue.
+ * slave slave port
+ * buffer for packets
+ * size number of packets to be injected
+ * return number of queued packets or negative error number
+ */
+static int
+slave_put_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_ring_enqueue_burst(slave->rx_queue, (void **)buf, size);
+}
+
+static uint16_t
+bond_rx(struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_eth_rx_burst(test_params.bonded_port_id, 0, buf, size);
+}
+
+static uint16_t
+bond_tx(struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_eth_tx_burst(test_params.bonded_port_id, 0, buf, size);
+}
+
+static void
+free_pkts(struct rte_mbuf **pkts, uint16_t count)
+{
+ uint16_t i;
+
+ for (i = 0; i < count; i++) {
+ if (pkts[i] != NULL)
+ rte_pktmbuf_free(pkts[i]);
+ }
+}
+
+static int
+configure_ethdev(uint8_t port_id, uint8_t start)
+{
+ TEST_ASSERT(rte_eth_dev_configure(port_id, 1, 1, &default_pmd_conf) == 0,
+ "Failed to configure device %u", port_id);
+
+ TEST_ASSERT(rte_eth_rx_queue_setup(port_id, 0, RX_RING_SIZE,
+ rte_eth_dev_socket_id(port_id), NULL, test_params.mbuf_pool) == 0,
+ "Failed to setup rx queue.");
+
+ TEST_ASSERT(rte_eth_tx_queue_setup(port_id, 0, TX_RING_SIZE,
+ rte_eth_dev_socket_id(port_id), NULL) == 0,
+ "Failed to setup tx queue.");
+
+ if (start) {
+ TEST_ASSERT(rte_eth_dev_start(port_id) == 0,
+ "Failed to start device (%d).", port_id);
+ }
+ return 0;
+}
+
+static int
+add_slave(struct slave_conf *slave, uint8_t start)
+{
+ struct ether_addr addr, addr_check;
+
+ /* Some sanity check */
+ RTE_VERIFY(test_params.slave_ports <= slave &&
+ slave - test_params.slave_ports < (int)RTE_DIM(test_params.slave_ports));
+ RTE_VERIFY(slave->bonded == 0);
+ RTE_VERIFY(slave->port_id != INVALID_PORT_ID);
+
+ ether_addr_copy(&slave_mac_default, &addr);
+ addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+
+ rte_eth_dev_mac_addr_remove(slave->port_id, &addr);
+
+ TEST_ASSERT_SUCCESS(rte_eth_dev_mac_addr_add(slave->port_id, &addr, 0),
+ "Failed to set slave MAC address");
+
+ TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bonded_port_id,
+ slave->port_id),
+ "Failed to add slave (idx=%u, id=%u) to bonding (id=%u)",
+ (uint8_t)(slave - test_params.slave_ports), slave->port_id,
+ test_params.bonded_port_id);
+
+ slave->bonded = 1;
+ if (start) {
+ TEST_ASSERT_SUCCESS(rte_eth_dev_start(slave->port_id),
+ "Failed to start slave %u", slave->port_id);
+ }
+
+ rte_eth_macaddr_get(slave->port_id, &addr_check);
+ TEST_ASSERT_EQUAL(is_same_ether_addr(&addr, &addr_check), 1,
+ "Slave MAC address is not as expected");
+
+ RTE_VERIFY(slave->lacp_parnter_state == 0);
+ return 0;
+}
+
+static int
+remove_slave(struct slave_conf *slave)
+{
+ ptrdiff_t slave_idx = slave - test_params.slave_ports;
+
+ RTE_VERIFY(test_params.slave_ports <= slave &&
+ slave_idx < (ptrdiff_t)RTE_DIM(test_params.slave_ports));
+
+ RTE_VERIFY(slave->bonded == 1);
+ RTE_VERIFY(slave->port_id != INVALID_PORT_ID);
+
+ TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0,
+ "Slave %u tx queue not empty while removing from bonding.",
+ slave->port_id);
+
+ TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0,
+ "Slave %u tx queue not empty while removing from bonding.",
+ slave->port_id);
+
+ TEST_ASSERT_EQUAL(rte_eth_bond_slave_remove(test_params.bonded_port_id,
+ slave->port_id), 0,
+ "Failed to remove slave (idx=%u, id=%u) from bonding (id=%u)",
+ (uint8_t)slave_idx, slave->port_id,
+ test_params.bonded_port_id);
+
+ slave->bonded = 0;
+ slave->lacp_parnter_state = 0;
+ return 0;
+}
+
+static int
+initialize_bonded_device_with_slaves(uint8_t slave_count, uint8_t start)
+{
+ uint8_t i;
+
+ RTE_VERIFY(test_params.bonded_port_id != INVALID_PORT_ID);
+
+ for (i = 0; i < slave_count; i++) {
+ TEST_ASSERT_SUCCESS(add_slave(&test_params.slave_ports[i], 1),
+ "Failed to add port %u to bonded device.\n",
+ test_params.slave_ports[i].port_id);
+ }
+
+ /* Reset mode 4 configuration */
+ rte_eth_bond_8023ad_setup(test_params.bonded_port_id, NULL);
+ rte_eth_promiscuous_disable(test_params.bonded_port_id);
+
+ if (start)
+ TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bonded_port_id),
+ "Failed to start bonded device");
+
+ return TEST_SUCCESS;
+}
+
+static int
+remove_slaves_and_stop_bonded_device(void)
+{
+ struct slave_conf *slave;
+ int retval;
+ uint8_t slaves[RTE_MAX_ETHPORTS];
+ uint8_t i;
+
+ rte_eth_dev_stop(test_params.bonded_port_id);
+
+ FOR_EACH_SLAVE(i, slave)
+ remove_slave(slave);
+
+ retval = rte_eth_bond_slaves_get(test_params.bonded_port_id, slaves,
+ RTE_DIM(slaves));
+
+ TEST_ASSERT_EQUAL(retval, 0,
+ "Expected bonded device %u have 0 slaves but returned %d.",
+ test_params.bonded_port_id, retval);
+
+ FOR_EACH_PORT(i, slave) {
+ rte_eth_dev_stop(slave->port_id);
+
+ TEST_ASSERT(slave->bonded == 0,
+ "Port id=%u is still marked as enslaved.", slave->port_id);
+ }
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_setup(void)
+{
+ int retval, nb_mbuf_per_pool;
+ char name[RTE_ETH_NAME_MAX_LEN];
+ struct slave_conf *port;
+ const uint8_t socket_id = rte_socket_id();
+ uint8_t i;
+
+ if (test_params.mbuf_pool == NULL) {
+ nb_mbuf_per_pool = TEST_RX_DESC_MAX + DEF_PKT_BURST +
+ TEST_TX_DESC_MAX + MAX_PKT_BURST;
+ test_params.mbuf_pool = rte_mempool_create("TEST_MODE4",
+ nb_mbuf_per_pool, MBUF_SIZE, MBUF_CACHE_SIZE,
+ sizeof(struct rte_pktmbuf_pool_private),
+ rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
+ socket_id, 0);
+
+ TEST_ASSERT(test_params.mbuf_pool != NULL,
+ "rte_mempool_create failed\n");
+ }
+
+ /* Create / initialize ring eth devs. */
+ FOR_EACH_PORT(i, port) {
+ port = &test_params.slave_ports[i];
+
+ if (port->rx_queue == NULL) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_RX_QUEUE_FMT, i);
+ TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long");
+ port->rx_queue = rte_ring_create(name, RX_RING_SIZE, socket_id, 0);
+ TEST_ASSERT(port->rx_queue != NULL,
+ "Failed to allocate rx ring '%s': %s", name,
+ rte_strerror(rte_errno));
+ }
+
+ if (port->tx_queue == NULL) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_TX_QUEUE_FMT, i);
+ TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long");
+ port->tx_queue = rte_ring_create(name, TX_RING_SIZE, socket_id, 0);
+ TEST_ASSERT_NOT_NULL(port->tx_queue,
+ "Failed to allocate tx ring '%s': %s", name,
+ rte_strerror(rte_errno));
+ }
+
+ if (port->port_id == INVALID_PORT_ID) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_DEV_NAME_FMT, i);
+ TEST_ASSERT(retval < (int)RTE_DIM(name) - 1, "Name too long");
+ retval = rte_eth_from_rings(name, &port->rx_queue, 1,
+ &port->tx_queue, 1, socket_id);
+ TEST_ASSERT(retval >= 0,
+ "Failed to create ring ethdev '%s'\n", name);
+
+ port->port_id = rte_eth_dev_count() - 1;
+ }
+
+ retval = configure_ethdev(port->port_id, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to configure virtual ethdev %s\n",
+ name);
+ }
+
+ if (test_params.bonded_port_id == INVALID_PORT_ID) {
+ retval = rte_eth_bond_create(BONDED_DEV_NAME, BONDING_MODE_8023AD,
+ socket_id);
+
+ TEST_ASSERT(retval >= 0, "Failed to create bonded ethdev %s",
+ BONDED_DEV_NAME);
+
+ test_params.bonded_port_id = retval;
+ TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bonded_port_id, 0),
+ "Failed to configure bonded ethdev %s", BONDED_DEV_NAME);
+ } else if (rte_eth_bond_mode_get(test_params.bonded_port_id) !=
+ BONDING_MODE_8023AD) {
+ TEST_ASSERT(rte_eth_bond_mode_set(test_params.bonded_port_id,
+ BONDING_MODE_8023AD) == 0,
+ "Failed to set ethdev %d to mode %d",
+ test_params.bonded_port_id, BONDING_MODE_8023AD);
+ }
+
+ return 0;
+}
+
+static int
+testsuite_teardown(void)
+{
+ struct slave_conf *port;
+ uint8_t i;
+
+ /* Only stop ports.
+ * Any cleanup/reset state is done when particular test is
+ * started. */
+
+ rte_eth_dev_stop(test_params.bonded_port_id);
+
+ FOR_EACH_PORT(i, port)
+ rte_eth_dev_stop(port->port_id);
+
+ return 0;
+}
+
+/*
+ * Check if given LACP packet. If it is, make make replay packet to force
+ * COLLECTING state.
+ * return 0 when pkt is LACP frame, 1 if it is not slow frame, 2 if it is slow
+ * frame but not LACP
+ */
+static int
+make_lacp_reply(struct slave_conf *slave, struct rte_mbuf *pkt)
+{
+ struct ether_hdr *hdr;
+ struct slow_protocol_frame *slow_hdr;
+ struct lacpdu *lacp;
+
+ /* look for LACP */
+ hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ if (hdr->ether_type != rte_cpu_to_be_16(ETHER_TYPE_SLOW))
+ return 1;
+
+ slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *);
+ /* ignore packets of other types */
+ if (slow_hdr->slow_protocol.subtype != SLOW_SUBTYPE_LACP)
+ return 2;
+
+ slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *);
+
+ /* Change source address to partner address */
+ ether_addr_copy(&parnter_mac_default, &slow_hdr->eth_hdr.s_addr);
+ slow_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+
+ lacp = (struct lacpdu *) &slow_hdr->slow_protocol;
+ /* Save last received state */
+ slave->lacp_parnter_state = lacp->actor.state;
+ /* Change it into LACP replay by matching parameters. */
+ memcpy(&lacp->partner.port_params, &lacp->actor.port_params,
+ sizeof(struct port_params));
+
+ lacp->partner.state = lacp->actor.state;
+
+ ether_addr_copy(&parnter_system, &lacp->actor.port_params.system);
+ lacp->actor.state = STATE_LACP_ACTIVE |
+ STATE_SYNCHRONIZATION |
+ STATE_AGGREGATION |
+ STATE_COLLECTING |
+ STATE_DISTRIBUTING;
+
+ return 0;
+}
+
+/*
+ * Reads packets from given slave, search for LACP packet and reply them.
+ *
+ * Receives burst of packets from slave. Looks for LACP packet. Drops
+ * all other packets. Prepares response LACP and sends it back.
+ *
+ * return number of LACP received and replied, -1 on error.
+ */
+static int
+bond_handshake_reply(struct slave_conf *slave)
+{
+ int retval;
+ struct rte_mbuf *rx_buf[MAX_PKT_BURST];
+ struct rte_mbuf *lacp_tx_buf[MAX_PKT_BURST];
+ uint16_t lacp_tx_buf_cnt = 0, i;
+
+ retval = slave_get_pkts(slave, rx_buf, RTE_DIM(rx_buf));
+ TEST_ASSERT(retval >= 0, "Getting slave %u packets failed.",
+ slave->port_id);
+
+ for (i = 0; i < (uint16_t)retval; i++) {
+ if (make_lacp_reply(slave, rx_buf[i]) == 0) {
+ /* reply with actor's LACP */
+ lacp_tx_buf[lacp_tx_buf_cnt++] = rx_buf[i];
+ } else
+ rte_pktmbuf_free(rx_buf[i]);
+ }
+
+ if (lacp_tx_buf_cnt == 0)
+ return 0;
+
+ retval = slave_put_pkts(slave, lacp_tx_buf, lacp_tx_buf_cnt);
+ if (retval <= lacp_tx_buf_cnt) {
+ /* retval might be negative */
+ for (i = RTE_MAX(0, retval); retval < lacp_tx_buf_cnt; retval++)
+ rte_pktmbuf_free(lacp_tx_buf[i]);
+ }
+
+ TEST_ASSERT_EQUAL(retval, lacp_tx_buf_cnt,
+ "Failed to equeue lacp packets into slave %u tx queue.",
+ slave->port_id);
+
+ return lacp_tx_buf_cnt;
+}
+
+/*
+ * Function check if given slave tx queue contains packets that make mode 4
+ * handshake complete. It will drain slave queue.
+ * return 0 if handshake not completed, 1 if handshake was complete,
+ */
+static int
+bond_handshake_done(struct slave_conf *slave)
+{
+ const uint8_t expected_state = STATE_LACP_ACTIVE | STATE_SYNCHRONIZATION |
+ STATE_AGGREGATION | STATE_COLLECTING | STATE_DISTRIBUTING;
+
+ return slave->lacp_parnter_state == expected_state;
+}
+
+static unsigned
+bond_get_update_timeout_ms(void)
+{
+ struct rte_eth_bond_8023ad_conf conf;
+
+ rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf);
+ return conf.update_timeout_ms;
+}
+
+/*
+ * Exchanges LACP packets with partner to achieve dynamic port configuration.
+ * return TEST_SUCCESS if initial handshake succeed, TEST_FAILED otherwise.
+ */
+static int
+bond_handshake(void)
+{
+ struct slave_conf *slave;
+ struct rte_mbuf *buf[MAX_PKT_BURST];
+ uint16_t nb_pkts;
+ uint8_t all_slaves_done, i, j;
+ uint8_t status[RTE_DIM(test_params.slave_ports)] = { 0 };
+ const unsigned delay = bond_get_update_timeout_ms();
+
+ /* Exchange LACP frames */
+ all_slaves_done = 0;
+ for (i = 0; i < 30 && all_slaves_done == 0; ++i) {
+ rte_delay_ms(delay);
+
+ all_slaves_done = 1;
+ FOR_EACH_SLAVE(j, slave) {
+ /* If response already send, skip slave */
+ if (status[j] != 0)
+ continue;
+
+ if (bond_handshake_reply(slave) < 0) {
+ all_slaves_done = 0;
+ break;
+ }
+
+ status[j] = bond_handshake_done(slave);
+ if (status[j] == 0)
+ all_slaves_done = 0;
+ }
+
+ nb_pkts = bond_tx(NULL, 0);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets transmitted unexpectedly");
+
+ nb_pkts = bond_rx(buf, RTE_DIM(buf));
+ free_pkts(buf, nb_pkts);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets received unexpectedly");
+ }
+ /* If response didn't send - report failure */
+ TEST_ASSERT_EQUAL(all_slaves_done, 1, "Bond handshake failed\n");
+
+ /* If flags doesn't match - report failure */
+ return all_slaves_done = 1 ? TEST_SUCCESS : TEST_FAILED;
+}
+
+#define TEST_LACP_SLAVE_COUT RTE_DIM(test_params.slave_ports)
+static int
+test_mode4_lacp(void)
+{
+ int retval;
+
+ retval = initialize_bonded_device_with_slaves(TEST_LACP_SLAVE_COUT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ /* Test LACP handshake function */
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+generate_packets(struct ether_addr *src_mac,
+ struct ether_addr *dst_mac, uint16_t count, struct rte_mbuf **buf)
+{
+ uint16_t pktlen = PACKET_BURST_GEN_PKT_LEN;
+ uint8_t vlan_enable = 0;
+ uint16_t vlan_id = 0;
+ uint8_t ip4_type = 1; /* 0 - ipv6 */
+
+ uint16_t src_port = 10, dst_port = 20;
+
+ uint32_t ip_src[4] = { [0 ... 2] = 0xDEADBEEF, [3] = IPv4(192, 168, 0, 1) };
+ uint32_t ip_dst[4] = { [0 ... 2] = 0xFEEDFACE, [3] = IPv4(192, 168, 0, 2) };
+
+ struct ether_hdr pkt_eth_hdr;
+ struct udp_hdr pkt_udp_hdr;
+ union {
+ struct ipv4_hdr v4;
+ struct ipv6_hdr v6;
+ } pkt_ip_hdr;
+
+ int retval;
+
+ initialize_eth_header(&pkt_eth_hdr, src_mac, dst_mac, vlan_enable, vlan_id);
+
+ if (ip4_type)
+ initialize_ipv4_header(&pkt_ip_hdr.v4, ip_src[3], ip_dst[3], pktlen);
+ else
+ initialize_ipv6_header(&pkt_ip_hdr.v6, (uint8_t *)ip_src,
+ (uint8_t *)&ip_dst, pktlen);
+
+ initialize_udp_header(&pkt_udp_hdr, src_port, dst_port, 16);
+
+ retval = generate_packet_burst(test_params.mbuf_pool, buf,
+ &pkt_eth_hdr, vlan_enable, &pkt_ip_hdr, 1, &pkt_udp_hdr,
+ count, pktlen, 1);
+
+ if (retval > 0 && retval != count)
+ free_pkts(&buf[count - retval], retval);
+
+ TEST_ASSERT_EQUAL(retval, count, "Failed to generate %u packets",
+ count);
+
+ return count;
+}
+
+static int
+generate_and_put_packets(struct slave_conf *slave, struct ether_addr *src_mac,
+ struct ether_addr *dst_mac, uint16_t count)
+{
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+
+ retval = generate_packets(src_mac, dst_mac, count, pkts);
+ if (retval != (int)count)
+ return retval;
+
+ retval = slave_put_pkts(slave, pkts, count);
+ if (retval > 0 && retval != count)
+ free_pkts(&pkts[retval], count - retval);
+
+ TEST_ASSERT_EQUAL(retval, count,
+ "Failed to enqueue packets into slave %u RX queue", slave->port_id);
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_rx(void)
+{
+ struct slave_conf *slave;
+ uint16_t i, j;
+
+ uint16_t expected_pkts_cnt;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+ unsigned delay;
+
+ struct ether_hdr *hdr;
+
+ struct ether_addr src_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } };
+ struct ether_addr dst_mac;
+ struct ether_addr bonded_mac;
+
+ retval = initialize_bonded_device_with_slaves(TEST_PROMISC_SLAVE_COUNT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac);
+ ether_addr_copy(&bonded_mac, &dst_mac);
+
+ /* Assert that dst address is not bonding address */
+ dst_mac.addr_bytes[0]++;
+
+ /* First try with promiscuous mode enabled.
+ * Add 2 packets to each slave. First with bonding MAC address, second with
+ * different. Check if we received all of them. */
+ rte_eth_promiscuous_enable(test_params.bonded_port_id);
+
+ expected_pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ /* Expect 2 packets per slave */
+ expected_pkts_cnt += 2;
+ }
+
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval == expected_pkts_cnt) {
+ int cnt[2] = { 0, 0 };
+
+ for (i = 0; i < expected_pkts_cnt; i++) {
+ hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+ cnt[is_same_ether_addr(&hdr->d_addr, &bonded_mac)]++;
+ }
+
+ free_pkts(pkts, expected_pkts_cnt);
+
+ /* For division by 2 expected_pkts_cnt must be even */
+ RTE_VERIFY((expected_pkts_cnt & 1) == 0);
+ TEST_ASSERT(cnt[0] == expected_pkts_cnt / 2 &&
+ cnt[1] == expected_pkts_cnt / 2,
+ "Expected %u packets with the same MAC and %u with different but "
+ "got %u with the same and %u with diffrent MAC",
+ expected_pkts_cnt / 2, expected_pkts_cnt / 2, cnt[1], cnt[0]);
+ } else if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, expected_pkts_cnt,
+ "Expected %u packets but received only %d", expected_pkts_cnt, retval);
+
+ /* Now, disable promiscuous mode. When promiscuous mode is disabled we
+ * expect to receive only packets that are directed to bonding port. */
+ rte_eth_promiscuous_disable(test_params.bonded_port_id);
+
+ expected_pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ /* Expect only one packet per slave */
+ expected_pkts_cnt += 1;
+ }
+
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval == expected_pkts_cnt) {
+ int eq_cnt = 0;
+
+ for (i = 0; i < expected_pkts_cnt; i++) {
+ hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+ eq_cnt += is_same_ether_addr(&hdr->d_addr, &bonded_mac);
+ }
+
+ free_pkts(pkts, expected_pkts_cnt);
+ TEST_ASSERT_EQUAL(eq_cnt, expected_pkts_cnt, "Packet address mismatch");
+ } else if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, expected_pkts_cnt,
+ "Expected %u packets but received only %d", expected_pkts_cnt, retval);
+
+ /* Link down test: simulate link down for first slave. */
+ delay = bond_get_update_timeout_ms();
+
+ uint8_t slave_down_id = INVALID_PORT_ID;
+
+ /* Find first slave and make link down on it*/
+ FOR_EACH_SLAVE(i, slave) {
+ rte_eth_dev_set_link_down(slave->port_id);
+ slave_down_id = slave->port_id;
+ break;
+ }
+
+ RTE_VERIFY(slave_down_id != INVALID_PORT_ID);
+
+ /* Give some time to rearrange bonding */
+ for (i = 0; i < 3; i++) {
+ rte_delay_ms(delay);
+ bond_handshake();
+ }
+
+ TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed");
+
+ /* Put packet to each slave */
+ FOR_EACH_SLAVE(i, slave) {
+ void *pkt = NULL;
+
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst.");
+
+ src_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst.");
+
+ retval = bond_rx(pkts, RTE_DIM(pkts));
+
+ /* Clean anything */
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ while (rte_ring_dequeue(slave->rx_queue, (void **)&pkt) == 0)
+ rte_pktmbuf_free(pkt);
+
+ if (slave_down_id == slave->port_id)
+ TEST_ASSERT_EQUAL(retval, 0, "Packets received unexpectedly.");
+ else
+ TEST_ASSERT_NOT_EQUAL(retval, 0,
+ "Expected to receive some packets on slave %u.",
+ slave->port_id);
+ rte_eth_dev_start(slave->port_id);
+
+ for (j = 0; j < 5; j++) {
+ TEST_ASSERT(bond_handshake_reply(slave) >= 0,
+ "Handshake after link up");
+
+ if (bond_handshake_done(slave) == 1)
+ break;
+ }
+
+ TEST_ASSERT(j < 5, "Failed to agregate slave after link up");
+ }
+
+ remove_slaves_and_stop_bonded_device();
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_tx_burst(void)
+{
+ struct slave_conf *slave;
+ uint16_t i, j;
+
+ uint16_t exp_pkts_cnt, pkts_cnt = 0;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+ unsigned delay;
+
+ struct ether_addr dst_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } };
+ struct ether_addr bonded_mac;
+
+ retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac);
+
+ /* Prepare burst */
+ for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) {
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt;
+ retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]);
+
+ if (retval != 1)
+ free_pkts(pkts, pkts_cnt);
+
+ TEST_ASSERT_EQUAL(retval, 1, "Failed to generate packet %u", pkts_cnt);
+ }
+ exp_pkts_cnt = pkts_cnt;
+
+ /* Transmit packets on bonded device */
+ retval = bond_tx(pkts, pkts_cnt);
+ if (retval > 0 && retval < pkts_cnt)
+ free_pkts(&pkts[retval], pkts_cnt - retval);
+
+ TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed");
+
+ /* Check if packets were transmitted properly. Every slave should have
+ * at least one packet, and sum must match. Under normal operation
+ * there should be no LACP nor MARKER frames. */
+ pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ uint16_t normal_cnt, slow_cnt;
+
+ retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts));
+ normal_cnt = 0;
+ slow_cnt = 0;
+
+ for (j = 0; j < retval; j++) {
+ if (make_lacp_reply(slave, pkts[j]) == 1)
+ normal_cnt++;
+ else
+ slow_cnt++;
+ }
+
+ free_pkts(pkts, normal_cnt + slow_cnt);
+ TEST_ASSERT_EQUAL(slow_cnt, 0,
+ "slave %u unexpectedly transmitted %d SLOW packets", slave->port_id,
+ slow_cnt);
+
+ TEST_ASSERT_NOT_EQUAL(normal_cnt, 0,
+ "slave %u did not transmitted any packets", slave->port_id);
+
+ pkts_cnt += normal_cnt;
+ }
+
+ TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt,
+ "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt);
+
+ /* Link down test:
+ * simulate link down for first slave. */
+ delay = bond_get_update_timeout_ms();
+
+ uint8_t slave_down_id = INVALID_PORT_ID;
+
+ FOR_EACH_SLAVE(i, slave) {
+ rte_eth_dev_set_link_down(slave->port_id);
+ slave_down_id = slave->port_id;
+ break;
+ }
+
+ RTE_VERIFY(slave_down_id != INVALID_PORT_ID);
+
+ /* Give some time to rearrange bonding. */
+ for (i = 0; i < 3; i++) {
+ bond_handshake();
+ rte_delay_ms(delay);
+ }
+
+ TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed");
+
+ /* Prepare burst. */
+ for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) {
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt;
+ retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]);
+
+ if (retval != 1)
+ free_pkts(pkts, pkts_cnt);
+
+ TEST_ASSERT_EQUAL(retval, 1, "Failed to generate test packet %u",
+ pkts_cnt);
+ }
+ exp_pkts_cnt = pkts_cnt;
+
+ /* Transmit packets on bonded device. */
+ retval = bond_tx(pkts, pkts_cnt);
+ if (retval > 0 && retval < pkts_cnt)
+ free_pkts(&pkts[retval], pkts_cnt - retval);
+
+ TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed");
+
+ /* Check if packets was transmitted properly. Every slave should have
+ * at least one packet, and sum must match. Under normal operation
+ * there should be no LACP nor MARKER frames. */
+ pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ uint16_t normal_cnt, slow_cnt;
+
+ retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts));
+ normal_cnt = 0;
+ slow_cnt = 0;
+
+ for (j = 0; j < retval; j++) {
+ if (make_lacp_reply(slave, pkts[j]) == 1)
+ normal_cnt++;
+ else
+ slow_cnt++;
+ }
+
+ free_pkts(pkts, normal_cnt + slow_cnt);
+
+ if (slave_down_id == slave->port_id) {
+ TEST_ASSERT_EQUAL(normal_cnt + slow_cnt, 0,
+ "slave %u enexpectedly transmitted %u packets",
+ normal_cnt + slow_cnt, slave->port_id);
+ } else {
+ TEST_ASSERT_EQUAL(slow_cnt, 0,
+ "slave %u unexpectedly transmitted %d SLOW packets",
+ slave->port_id, slow_cnt);
+
+ TEST_ASSERT_NOT_EQUAL(normal_cnt, 0,
+ "slave %u did not transmitted any packets", slave->port_id);
+ }
+
+ pkts_cnt += normal_cnt;
+ }
+
+ TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt,
+ "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt);
+
+ return remove_slaves_and_stop_bonded_device();
+}
+
+static void
+init_marker(struct rte_mbuf *pkt, struct slave_conf *slave)
+{
+ struct marker_header *marker_hdr = rte_pktmbuf_mtod(pkt,
+ struct marker_header *);
+
+ /* Copy multicast destination address */
+ ether_addr_copy(&slow_protocol_mac_addr, &marker_hdr->eth_hdr.d_addr);
+
+ /* Init source address */
+ ether_addr_copy(&parnter_mac_default, &marker_hdr->eth_hdr.s_addr);
+ marker_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN-1] = slave->port_id;
+
+ marker_hdr->eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_SLOW);
+
+ marker_hdr->marker.subtype = SLOW_SUBTYPE_MARKER;
+ marker_hdr->marker.version_number = 1;
+ marker_hdr->marker.tlv_type_marker = MARKER_TLV_TYPE_INFO;
+ marker_hdr->marker.info_length =
+ offsetof(struct marker, reserved_90) -
+ offsetof(struct marker, requester_port);
+ RTE_VERIFY(marker_hdr->marker.info_length == 16);
+ marker_hdr->marker.requester_port = slave->port_id + 1;
+ marker_hdr->marker.tlv_type_terminator = TLV_TYPE_TERMINATOR_INFORMATION;
+ marker_hdr->marker.terminator_length = 0;
+}
+
+static int
+test_mode4_marker(void)
+{
+ struct slave_conf *slave;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ struct rte_mbuf *marker_pkt;
+ struct marker_header *marker_hdr;
+
+ unsigned delay;
+ int retval;
+ uint16_t nb_pkts;
+ uint8_t i, j;
+ const uint16_t ethtype_slow_be = rte_be_to_cpu_16(ETHER_TYPE_SLOW);
+
+ retval = initialize_bonded_device_with_slaves(TEST_MARKER_SLAVE_COUT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ /* Test LACP handshake function */
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ delay = bond_get_update_timeout_ms();
+ FOR_EACH_SLAVE(i, slave) {
+ marker_pkt = rte_pktmbuf_alloc(test_params.mbuf_pool);
+ TEST_ASSERT_NOT_NULL(marker_pkt, "Failed to allocate marker packet");
+ init_marker(marker_pkt, slave);
+
+ retval = slave_put_pkts(slave, &marker_pkt, 1);
+ if (retval != 1)
+ rte_pktmbuf_free(marker_pkt);
+
+ TEST_ASSERT_EQUAL(retval, 1,
+ "Failed to send marker packet to slave %u", slave->port_id);
+
+ for (j = 0; j < 20; ++j) {
+ rte_delay_ms(delay);
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 0, "Received packets unexpectedly");
+
+ retval = rte_eth_tx_burst(test_params.bonded_port_id, 0, NULL, 0);
+ TEST_ASSERT_EQUAL(retval, 0,
+ "Requested TX of 0 packets but %d transmitted", retval);
+
+ /* Check if LACP packet was send by state machines
+ First and only packet must be a maker response */
+ retval = slave_get_pkts(slave, pkts, MAX_PKT_BURST);
+ if (retval == 0)
+ continue;
+ if (retval > 1)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 1, "failed to get slave packets");
+ nb_pkts = retval;
+
+ marker_hdr = rte_pktmbuf_mtod(pkts[0], struct marker_header *);
+ /* Check if it's slow packet*/
+ if (marker_hdr->eth_hdr.ether_type != ethtype_slow_be)
+ retval = -1;
+ /* Check if it's marker packet */
+ else if (marker_hdr->marker.subtype != SLOW_SUBTYPE_MARKER)
+ retval = -2;
+ else if (marker_hdr->marker.tlv_type_marker != MARKER_TLV_TYPE_RESP)
+ retval = -3;
+
+ free_pkts(pkts, nb_pkts);
+
+ TEST_ASSERT_NOT_EQUAL(retval, -1, "Unexpected protocol type");
+ TEST_ASSERT_NOT_EQUAL(retval, -2, "Unexpected sub protocol type");
+ TEST_ASSERT_NOT_EQUAL(retval, -3, "Unexpected marker type");
+ break;
+ }
+
+ TEST_ASSERT(j < 20, "Marker response not found");
+ }
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_expired(void)
+{
+ struct slave_conf *slave, *exp_slave = NULL;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ struct rte_mbuf *pkt = NULL;
+ int retval;
+ uint32_t old_delay;
+
+ uint8_t i;
+ uint16_t j;
+
+ struct rte_eth_bond_8023ad_conf conf;
+
+ retval = initialize_bonded_device_with_slaves(TEST_EXPIRED_SLAVE_COUNT, 1);
+ /* Set custom timeouts to make test last shorter. */
+ rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf);
+ conf.fast_periodic_ms = 100;
+ conf.slow_periodic_ms = 600;
+ conf.short_timeout_ms = 300;
+ conf.long_timeout_ms = 900;
+ conf.aggregate_wait_timeout_ms = 200;
+ conf.tx_period_ms = 100;
+ old_delay = conf.update_timeout_ms;
+ conf.update_timeout_ms = 10;
+ rte_eth_bond_8023ad_setup(test_params.bonded_port_id, &conf);
+
+ /* Wait for new settings to be applied. */
+ for (i = 0; i < old_delay/conf.update_timeout_ms * 2; i++) {
+ FOR_EACH_SLAVE(j, slave)
+ bond_handshake_reply(slave);
+
+ rte_delay_ms(conf.update_timeout_ms);
+ }
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ /* Find first slave */
+ FOR_EACH_SLAVE(i, slave) {
+ exp_slave = slave;
+ break;
+ }
+
+ RTE_VERIFY(exp_slave != NULL);
+
+ /* When one of partners do not send or respond to LACP frame in
+ * conf.long_timeout_ms time, internal state machines should detect this
+ * and transit to expired state. */
+ for (j = 0; j < conf.long_timeout_ms/conf.update_timeout_ms + 2; j++) {
+ rte_delay_ms(conf.update_timeout_ms);
+
+ retval = bond_tx(NULL, 0);
+ TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets",
+ retval);
+
+ FOR_EACH_SLAVE(i, slave) {
+ retval = bond_handshake_reply(slave);
+ TEST_ASSERT(retval >= 0, "Handshake failed");
+
+ /* Remove replay for slave that supose to be expired. */
+ if (slave == exp_slave) {
+ while (rte_ring_count(slave->rx_queue) > 0) {
+ rte_ring_dequeue(slave->rx_queue, (void **)&pkt);
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+
+ retval = bond_rx(pkts, RTE_DIM(pkts));
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets",
+ retval);
+ }
+
+ /* After test only expected slave should be in EXPIRED state */
+ FOR_EACH_SLAVE(i, slave) {
+ if (slave == exp_slave)
+ TEST_ASSERT(slave->lacp_parnter_state & STATE_EXPIRED,
+ "Slave %u should be in expired.", slave->port_id);
+ else
+ TEST_ASSERT_EQUAL(bond_handshake_done(slave), 1,
+ "Slave %u should be operational.", slave->port_id);
+ }
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+check_environment(void)
+{
+ struct slave_conf *port;
+ uint8_t i, env_state;
+ uint8_t slaves[RTE_DIM(test_params.slave_ports)];
+ int slaves_count;
+
+ env_state = 0;
+ FOR_EACH_PORT(i, port) {
+ if (rte_ring_count(port->rx_queue) != 0)
+ env_state |= 0x01;
+
+ if (rte_ring_count(port->tx_queue) != 0)
+ env_state |= 0x02;
+
+ if (port->bonded != 0)
+ env_state |= 0x04;
+
+ if (port->lacp_parnter_state != 0)
+ env_state |= 0x08;
+
+ if (env_state != 0)
+ break;
+ }
+
+ slaves_count = rte_eth_bond_slaves_get(test_params.bonded_port_id,
+ slaves, RTE_DIM(slaves));
+
+ if (slaves_count != 0)
+ env_state |= 0x10;
+
+ TEST_ASSERT_EQUAL(env_state, 0,
+ "Environment not clean (port %u):%s%s%s%s%s",
+ port->port_id,
+ env_state & 0x01 ? " slave rx queue not clean" : "",
+ env_state & 0x02 ? " slave tx queue not clean" : "",
+ env_state & 0x04 ? " port marked as enslaved" : "",
+ env_state & 0x80 ? " slave state is not reset" : "",
+ env_state & 0x10 ? " slave count not equal 0" : ".");
+
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_executor(int (*test_func)(void))
+{
+ struct slave_conf *port;
+ int test_result;
+ uint8_t i;
+ void *pkt;
+
+ /* Check if environment is clean. Fail to launch a test if there was
+ * a critical error before that prevented to reset environment. */
+ TEST_ASSERT_SUCCESS(check_environment(),
+ "Refusing to launch test in dirty environment.");
+
+ RTE_VERIFY(test_func != NULL);
+ test_result = (*test_func)();
+
+ /* If test succeed check if environment wast left in good condition. */
+ if (test_result == TEST_SUCCESS)
+ test_result = check_environment();
+
+ /* Reset environment in case test failed to do that. */
+ if (test_result != TEST_SUCCESS) {
+ TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(),
+ "Failed to stop bonded device");
+
+ FOR_EACH_PORT(i, port) {
+ while (rte_ring_count(port->rx_queue) != 0) {
+ if (rte_ring_dequeue(port->rx_queue, &pkt) == 0)
+ rte_pktmbuf_free(pkt);
+ }
+
+ while (rte_ring_count(port->tx_queue) != 0) {
+ if (rte_ring_dequeue(port->tx_queue, &pkt) == 0)
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+
+ return test_result;
+}
+
+static int
+test_mode4_lacp_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_lacp);
+}
+
+static int
+test_mode4_marker_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_marker);
+}
+
+static int
+test_mode4_rx_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_rx);
+}
+
+static int
+test_mode4_tx_burst_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_tx_burst);
+}
+
+static int
+test_mode4_expired_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_expired);
+}
+
+static struct unit_test_suite link_bonding_mode4_test_suite = {
+ .suite_name = "Link Bonding mode 4 Unit Test Suite",
+ .setup = test_setup,
+ .teardown = testsuite_teardown,
+ .unit_test_cases = {
+ TEST_CASE_NAMED("test_mode4_lacp", test_mode4_lacp_wrapper),
+ TEST_CASE_NAMED("test_mode4_rx", test_mode4_rx_wrapper),
+ TEST_CASE_NAMED("test_mode4_tx_burst", test_mode4_tx_burst_wrapper),
+ TEST_CASE_NAMED("test_mode4_marker", test_mode4_marker_wrapper),
+ TEST_CASE_NAMED("test_mode4_expired", test_mode4_expired_wrapper),
+ { NULL, NULL, NULL, NULL, NULL } /**< NULL terminate unit test array */
+ }
+};
+
+static int
+test_link_bonding_mode4(void)
+{
+ return unit_test_suite_runner(&link_bonding_mode4_test_suite);
+}
+
+static struct test_command link_bonding_cmd = {
+ .command = "link_bonding_mode4_autotest",
+ .callback = test_link_bonding_mode4,
+};
+
+REGISTER_TEST_COMMAND(link_bonding_cmd);
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests
2014-12-12 9:14 [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests Michal Jastrzebski
` (2 preceding siblings ...)
2014-12-12 9:14 ` [dpdk-dev] [PATCH 3/3] unit tests add mode 4 unit test Michal Jastrzebski
@ 2014-12-12 15:27 ` Doherty, Declan
3 siblings, 0 replies; 30+ messages in thread
From: Doherty, Declan @ 2014-12-12 15:27 UTC (permalink / raw)
To: Jastrzebski, MichalX K, dev
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Michal Jastrzebski
> Sent: Friday, December 12, 2014 9:15 AM
> To: dev@dpdk.org
> Cc: Kulasek, TomaszX
> Subject: [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests
>
> These patches add unit tests for mode 4. They also changes ring pmd
> to behave more like ordinary pmd device.
>
> Pawel Wodkowski (3):
> bond-change-warning
> PMD-ring-MAC-management-fix-initialization-link-up-d
> unit-tests-add-mode-4-unit-test
>
> app/test/Makefile | 1 +
> app/test/test.h | 111 ++-
> app/test/test_link_bonding.c | 2 +-
> app/test/test_link_bonding_mode4.c | 1412
> ++++++++++++++++++++++++++++++++
> lib/librte_pmd_bond/rte_eth_bond_pmd.c | 4 +-
> lib/librte_pmd_ring/rte_eth_ring.c | 62 +-
> 6 files changed, 1539 insertions(+), 53 deletions(-)
> create mode 100644 app/test/test_link_bonding_mode4.c
>
> --
> 1.7.9.5
Acked-by: Declan Doherty <declan.doherty@intel.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH 2/3] PMD ring MAC management, fix initialization, link up/down
2014-12-12 9:14 ` [dpdk-dev] [PATCH 2/3] PMD ring MAC management, fix initialization, link up/down Michal Jastrzebski
@ 2015-01-15 10:53 ` Thomas Monjalon
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 0/3] " Tomasz Kulasek
1 sibling, 0 replies; 30+ messages in thread
From: Thomas Monjalon @ 2015-01-15 10:53 UTC (permalink / raw)
To: Michal Jastrzebski, tomaszx.kulasek, Pawel Wodkowski; +Cc: dev
2014-12-12 09:14, Michal Jastrzebski:
> * add MAC management per device
> * fix initialization procedure
> * add link up/down functions
>
> Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
> Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Please, split this patch: only 1 feature per patch.
Thanks
--
Thomas
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH 3/3] unit tests add mode 4 unit test
2014-12-12 9:14 ` [dpdk-dev] [PATCH 3/3] unit tests add mode 4 unit test Michal Jastrzebski
@ 2015-01-15 10:55 ` Thomas Monjalon
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 0/2] " Tomasz Kulasek
1 sibling, 0 replies; 30+ messages in thread
From: Thomas Monjalon @ 2015-01-15 10:55 UTC (permalink / raw)
To: Michal Jastrzebski, Pawel Wodkowski; +Cc: dev
2014-12-12 09:14, Michal Jastrzebski:
[...]
> Additionally some typos fix is included.
>
> Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
> ---
> app/test/Makefile | 1 +
> app/test/test.h | 111 +--
> app/test/test_link_bonding.c | 2 +-
> app/test/test_link_bonding_mode4.c | 1412 ++++++++++++++++++++++++++++++++++++
Please do not mix a test addition with a reworking of test.h.
Thanks
--
Thomas
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v2 0/3] PMD ring MAC management, fix initialization, link up/down
2014-12-12 9:14 ` [dpdk-dev] [PATCH 2/3] PMD ring MAC management, fix initialization, link up/down Michal Jastrzebski
2015-01-15 10:53 ` Thomas Monjalon
@ 2015-01-19 11:56 ` Tomasz Kulasek
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 1/3] PMD Ring - Add link up/down functions Tomasz Kulasek
` (3 more replies)
1 sibling, 4 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-19 11:56 UTC (permalink / raw)
To: dev
Patch split into smaller parts to separate features from previous version.
Tomasz Kulasek (3):
PMD Ring - Add link up/down functions
PMD Ring - Add MAC addr add/remove functions
PMD Ring - Fix for per device management
lib/librte_pmd_ring/rte_eth_ring.c | 62 +++++++++++++++++++++++++++++++++---
1 file changed, 57 insertions(+), 5 deletions(-)
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v2 1/3] PMD Ring - Add link up/down functions
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 0/3] " Tomasz Kulasek
@ 2015-01-19 11:56 ` Tomasz Kulasek
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 2/3] PMD Ring - Add MAC addr add/remove functions Tomasz Kulasek
` (2 subsequent siblings)
3 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-19 11:56 UTC (permalink / raw)
To: dev
Link up and down implementation.
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
lib/librte_pmd_ring/rte_eth_ring.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/lib/librte_pmd_ring/rte_eth_ring.c b/lib/librte_pmd_ring/rte_eth_ring.c
index 4f1b6ed..929e71a 100644
--- a/lib/librte_pmd_ring/rte_eth_ring.c
+++ b/lib/librte_pmd_ring/rte_eth_ring.c
@@ -121,6 +121,20 @@ eth_dev_stop(struct rte_eth_dev *dev)
}
static int
+eth_dev_set_link_down(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = 0;
+ return 0;
+}
+
+static int
+eth_dev_set_link_up(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = 1;
+ return 0;
+}
+
+static int
eth_rx_queue_setup(struct rte_eth_dev *dev,uint16_t rx_queue_id,
uint16_t nb_rx_desc __rte_unused,
unsigned int socket_id __rte_unused,
@@ -207,6 +221,8 @@ eth_link_update(struct rte_eth_dev *dev __rte_unused,
static struct eth_dev_ops ops = {
.dev_start = eth_dev_start,
.dev_stop = eth_dev_stop,
+ .dev_set_link_up = eth_dev_set_link_up,
+ .dev_set_link_down = eth_dev_set_link_down,
.dev_configure = eth_dev_configure,
.dev_infos_get = eth_dev_info,
.rx_queue_setup = eth_rx_queue_setup,
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v2 2/3] PMD Ring - Add MAC addr add/remove functions
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 0/3] " Tomasz Kulasek
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 1/3] PMD Ring - Add link up/down functions Tomasz Kulasek
@ 2015-01-19 11:56 ` Tomasz Kulasek
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 3/3] PMD Ring - Fix for MAC per device management Tomasz Kulasek
2015-01-28 11:56 ` [dpdk-dev] [PATCH v2 0/3] PMD ring MAC management, fix initialization, link up/down Doherty, Declan
3 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-19 11:56 UTC (permalink / raw)
To: dev
Added MAC addr add/remove dummy callbacks.
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
lib/librte_pmd_ring/rte_eth_ring.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/lib/librte_pmd_ring/rte_eth_ring.c b/lib/librte_pmd_ring/rte_eth_ring.c
index 929e71a..91e1964 100644
--- a/lib/librte_pmd_ring/rte_eth_ring.c
+++ b/lib/librte_pmd_ring/rte_eth_ring.c
@@ -213,6 +213,20 @@ eth_stats_reset(struct rte_eth_dev *dev)
}
static void
+eth_mac_addr_remove(struct rte_eth_dev *dev __rte_unused,
+ uint32_t index __rte_unused)
+{
+}
+
+static void
+eth_mac_addr_add(struct rte_eth_dev *dev __rte_unused,
+ struct ether_addr *mac_addr __rte_unused,
+ uint32_t index __rte_unused,
+ uint32_t vmdq __rte_unused)
+{
+}
+
+static void
eth_queue_release(void *q __rte_unused) { ; }
static int
eth_link_update(struct rte_eth_dev *dev __rte_unused,
@@ -232,6 +246,8 @@ static struct eth_dev_ops ops = {
.link_update = eth_link_update,
.stats_get = eth_stats_get,
.stats_reset = eth_stats_reset,
+ .mac_addr_remove = eth_mac_addr_remove,
+ .mac_addr_add = eth_mac_addr_add,
};
int
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v2 3/3] PMD Ring - Fix for MAC per device management
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 0/3] " Tomasz Kulasek
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 1/3] PMD Ring - Add link up/down functions Tomasz Kulasek
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 2/3] PMD Ring - Add MAC addr add/remove functions Tomasz Kulasek
@ 2015-01-19 11:56 ` Tomasz Kulasek
2015-01-28 11:56 ` [dpdk-dev] [PATCH v2 0/3] PMD ring MAC management, fix initialization, link up/down Doherty, Declan
3 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-19 11:56 UTC (permalink / raw)
To: dev
Initialization procedure fix to allow per device MAC configuration.
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
lib/librte_pmd_ring/rte_eth_ring.c | 30 +++++++++++++++++++++++++-----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/lib/librte_pmd_ring/rte_eth_ring.c b/lib/librte_pmd_ring/rte_eth_ring.c
index 91e1964..b6047cc 100644
--- a/lib/librte_pmd_ring/rte_eth_ring.c
+++ b/lib/librte_pmd_ring/rte_eth_ring.c
@@ -44,6 +44,8 @@
#define ETH_RING_ACTION_CREATE "CREATE"
#define ETH_RING_ACTION_ATTACH "ATTACH"
+static const char *ring_ethdev_driver_name = "Ring PMD";
+
static const char *valid_arguments[] = {
ETH_RING_NUMA_NODE_ACTION_ARG,
NULL
@@ -62,10 +64,11 @@ struct pmd_internals {
struct ring_queue rx_ring_queues[RTE_PMD_RING_MAX_RX_RINGS];
struct ring_queue tx_ring_queues[RTE_PMD_RING_MAX_TX_RINGS];
+
+ struct ether_addr address;
};
-static struct ether_addr eth_addr = { .addr_bytes = {0} };
static const char *drivername = "Rings PMD";
static struct rte_eth_link pmd_link = {
.link_speed = 10000,
@@ -261,6 +264,9 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
struct rte_pci_device *pci_dev = NULL;
struct pmd_internals *internals = NULL;
struct rte_eth_dev *eth_dev = NULL;
+ struct eth_driver *eth_drv = NULL;
+ struct rte_pci_id *id_table = NULL;
+
unsigned i;
/* do some parameter checking */
@@ -283,6 +289,10 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
if (pci_dev == NULL)
goto error;
+ id_table = rte_zmalloc_socket(name, sizeof(*id_table), 0, numa_node);
+ if (id_table == NULL)
+ goto error;
+
internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
if (internals == NULL)
goto error;
@@ -292,6 +302,10 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
if (eth_dev == NULL)
goto error;
+ eth_drv = rte_zmalloc_socket(name, sizeof(*eth_drv), 0, numa_node);
+ if (eth_drv == NULL)
+ goto error;
+
/* now put it all together
* - store queue data in internals,
* - store numa_node info in pci_driver
@@ -310,18 +324,24 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
internals->tx_ring_queues[i].rng = tx_queues[i];
}
+ eth_drv->pci_drv.name = ring_ethdev_driver_name;
+ eth_drv->pci_drv.id_table = id_table;
+
pci_dev->numa_node = numa_node;
+ pci_dev->driver = ð_drv->pci_drv;
data->dev_private = internals;
data->port_id = eth_dev->data->port_id;
data->nb_rx_queues = (uint16_t)nb_rx_queues;
data->nb_tx_queues = (uint16_t)nb_tx_queues;
data->dev_link = pmd_link;
- data->mac_addrs = ð_addr;
+ data->mac_addrs = &internals->address;
- eth_dev ->data = data;
- eth_dev ->dev_ops = &ops;
- eth_dev ->pci_dev = pci_dev;
+ eth_dev->data = data;
+ eth_dev->driver = eth_drv;
+ eth_dev->dev_ops = &ops;
+ eth_dev->pci_dev = pci_dev;
+ TAILQ_INIT(&(eth_dev->callbacks));
/* finally assign rx and tx ops */
eth_dev->rx_pkt_burst = eth_ring_rx;
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v2 0/2] unit tests add mode 4 unit test
2014-12-12 9:14 ` [dpdk-dev] [PATCH 3/3] unit tests add mode 4 unit test Michal Jastrzebski
2015-01-15 10:55 ` Thomas Monjalon
@ 2015-01-19 12:43 ` Tomasz Kulasek
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 1/2] Unit tests - test.h rework Tomasz Kulasek
` (2 more replies)
1 sibling, 3 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-19 12:43 UTC (permalink / raw)
To: dev
Update v2:
Patch split - separated test.h rework and unit test for mode 4 patch.
Tomasz Kulasek (2):
Unit tests - test.h rework
Unit tests for mode 4
app/test/Makefile | 1 +
app/test/test.h | 112 +--
app/test/test_link_bonding.c | 2 +-
app/test/test_link_bonding_mode4.c | 1412 ++++++++++++++++++++++++++++++++++++
4 files changed, 1480 insertions(+), 47 deletions(-)
create mode 100644 app/test/test_link_bonding_mode4.c
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v2 1/2] Unit tests - test.h rework
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 0/2] " Tomasz Kulasek
@ 2015-01-19 12:43 ` Tomasz Kulasek
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 2/2] Unit tests for mode 4 Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 0/3] " Tomasz Kulasek
2 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-19 12:43 UTC (permalink / raw)
To: dev
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
app/test/test.h | 112 ++++++++++++++++++++++++++++++++-----------------------
1 file changed, 66 insertions(+), 46 deletions(-)
diff --git a/app/test/test.h b/app/test/test.h
index 896f7db..5450986 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -36,62 +36,79 @@
#include <sys/queue.h>
-#define TEST_ASSERT(cond, msg, ...) do { \
- if (!(cond)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
-} while (0)
+#define TEST_SUCCESS (0)
+#define TEST_FAILED (-1)
+
+/* Before including test.h file you can define
+ * TEST_TRACE_FAILURE(_file, _line, _func) macro to better trace/debug test
+ * failures. Mostly useful in test development phase. */
+#ifndef TEST_TRACE_FAILURE
+# define TEST_TRACE_FAILURE(_file, _line, _func)
+#endif
-#define TEST_ASSERT_EQUAL(a, b, msg, ...) do { \
- if (!(a == b)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT(cond, msg, ...) do { \
+ if (!(cond)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_NOT_EQUAL(a, b, msg, ...) do { \
- if (!(a != b)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_EQUAL(a, b, msg, ...) do { \
+ if (!(a == b)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \
- if (!(val == 0)) { \
- printf("TestCase %s() line %d failed (err %d): " \
- msg "\n", __func__, __LINE__, val, \
- ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NOT_EQUAL(a, b, msg, ...) do { \
+ if (!(a != b)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_FAIL(val, msg, ...) do { \
- if (!(val != 0)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \
+ typeof(val) _val = (val); \
+ if (!(_val == 0)) { \
+ printf("TestCase %s() line %d failed (err %d): " \
+ msg "\n", __func__, __LINE__, _val, \
+ ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
+#define TEST_ASSERT_FAIL(val, msg, ...) do { \
+ if (!(val != 0)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
+} while (0)
-#define TEST_ASSERT_NULL(val, msg, ...) do { \
- if (!(val == NULL)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NULL(val, msg, ...) do { \
+ if (!(val == NULL)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \
- if (!(val != NULL)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \
+ if (!(val != NULL)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
struct unit_test_case {
@@ -104,8 +121,11 @@ struct unit_test_case {
#define TEST_CASE(fn) { NULL, NULL, fn, #fn " succeeded", #fn " failed"}
-#define TEST_CASE_ST(setup, teardown, testcase) \
- { setup, teardown, testcase, #testcase " succeeded", \
+#define TEST_CASE_NAMED(name, fn) { NULL, NULL, fn, name " succeeded", \
+ name " failed"}
+
+#define TEST_CASE_ST(setup, teardown, testcase) \
+ { setup, teardown, testcase, #testcase " succeeded", \
#testcase " failed "}
#define TEST_CASES_END() { NULL, NULL, NULL, NULL, NULL }
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v2 2/2] Unit tests for mode 4
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 0/2] " Tomasz Kulasek
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 1/2] Unit tests - test.h rework Tomasz Kulasek
@ 2015-01-19 12:43 ` Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 0/3] " Tomasz Kulasek
2 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-19 12:43 UTC (permalink / raw)
To: dev
This patch adds unit tests for mode 4. It is split into separate
file to avoid problems with other modes that does not need to
look into packets payload.
This patch includes also a modification of maximum number of ports
used in their tests for bonding modes 0-3 from 16 to 6.
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
app/test/Makefile | 1 +
app/test/test_link_bonding.c | 2 +-
app/test/test_link_bonding_mode4.c | 1412 ++++++++++++++++++++++++++++++++++++
3 files changed, 1414 insertions(+), 1 deletion(-)
create mode 100644 app/test/test_link_bonding_mode4.c
diff --git a/app/test/Makefile b/app/test/Makefile
index 4311f96..ee0e95a 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -129,6 +129,7 @@ SRCS-y += virtual_pmd.c
SRCS-y += packet_burst_generator.c
SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding_mode4.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring.c
SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index 4523de6..6d5b383 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -57,7 +57,7 @@
#include "test.h"
-#define TEST_MAX_NUMBER_OF_PORTS (16)
+#define TEST_MAX_NUMBER_OF_PORTS (6)
#define RX_RING_SIZE 128
#define RX_FREE_THRESH 32
diff --git a/app/test/test_link_bonding_mode4.c b/app/test/test_link_bonding_mode4.c
new file mode 100644
index 0000000..f8d0955
--- /dev/null
+++ b/app/test/test_link_bonding_mode4.c
@@ -0,0 +1,1412 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <rte_cycles.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_memory.h>
+
+#include <rte_string_fns.h>
+
+#include <rte_eth_ring.h>
+#include <rte_errno.h>
+#include <rte_eth_bond.h>
+#include <rte_eth_bond_8023ad.h>
+
+#include "packet_burst_generator.h"
+
+#include "test.h"
+
+#define SLAVE_COUNT (4)
+
+#define RX_RING_SIZE 128
+#define TX_RING_SIZE 512
+
+#define MBUF_PAYLOAD_SIZE (2048)
+#define MBUF_SIZE (MBUF_PAYLOAD_SIZE + sizeof(struct rte_mbuf) + \
+ RTE_PKTMBUF_HEADROOM)
+#define MBUF_CACHE_SIZE (250)
+#define BURST_SIZE (32)
+
+#define DEFAULT_MBUF_DATA_SIZE (2048)
+#define TEST_RX_DESC_MAX (2048)
+#define TEST_TX_DESC_MAX (2048)
+#define MAX_PKT_BURST (32)
+#define DEF_PKT_BURST (16)
+
+#define BONDED_DEV_NAME ("unit_test_mode4_bond_dev")
+
+#define SLAVE_DEV_NAME_FMT ("unit_test_mode4_slave_%d")
+#define SLAVE_RX_QUEUE_FMT ("unit_test_mode4_slave_%d_rx")
+#define SLAVE_TX_QUEUE_FMT ("unit_test_mode4_slave_%d_tx")
+
+#define INVALID_SOCKET_ID (-1)
+#define INVALID_PORT_ID (0xFF)
+#define INVALID_BONDING_MODE (-1)
+
+static const struct ether_addr slave_mac_default = {
+ { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 }
+};
+
+static const struct ether_addr parnter_mac_default = {
+ { 0x22, 0xBB, 0xFF, 0xBB, 0x00, 0x00 }
+};
+
+static const struct ether_addr parnter_system = {
+ { 0x33, 0xFF, 0xBB, 0xFF, 0x00, 0x00 }
+};
+
+static const struct ether_addr slow_protocol_mac_addr = {
+ { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 }
+};
+
+struct slave_conf {
+ struct rte_ring *rx_queue;
+ struct rte_ring *tx_queue;
+ uint8_t port_id;
+ uint8_t bonded : 1;
+
+ uint8_t lacp_parnter_state;
+};
+
+struct ether_vlan_hdr {
+ struct ether_hdr pkt_eth_hdr;
+ struct vlan_hdr vlan_hdr;
+};
+
+struct link_bonding_unittest_params {
+ uint8_t bonded_port_id;
+ struct slave_conf slave_ports[SLAVE_COUNT];
+
+ struct rte_mempool *mbuf_pool;
+};
+
+#define TEST_DEFAULT_SLAVE_COUNT RTE_DIM(test_params.slave_ports)
+#define TEST_RX_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_TX_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_MARKER_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_EXPIRED_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_PROMISC_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+
+static struct link_bonding_unittest_params test_params = {
+ .bonded_port_id = INVALID_PORT_ID,
+ .slave_ports = { [0 ... SLAVE_COUNT - 1] = { .port_id = INVALID_PORT_ID} },
+
+ .mbuf_pool = NULL,
+};
+
+static struct rte_eth_conf default_pmd_conf = {
+ .rxmode = {
+ .mq_mode = ETH_MQ_RX_NONE,
+ .max_rx_pkt_len = ETHER_MAX_LEN,
+ .split_hdr_size = 0,
+ .header_split = 0, /**< Header Split disabled */
+ .hw_ip_checksum = 0, /**< IP checksum offload enabled */
+ .hw_vlan_filter = 0, /**< VLAN filtering disabled */
+ .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /**< CRC stripped by hardware */
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+ .lpbk_mode = 0,
+};
+
+#define FOR_EACH(_i, _item, _array, _size) \
+ for (_i = 0, _item = &_array[0]; _i < _size && (_item = &_array[_i]); _i++)
+
+/* Macro for iterating over every port that can be used as a slave
+ * in this test.
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ */
+#define FOR_EACH_PORT(_i, _port) \
+ FOR_EACH(_i, _port, test_params.slave_ports, \
+ RTE_DIM(test_params.slave_ports))
+
+/* Macro for iterating over every port that can be used as a slave
+ * in this test and satisfy given condition.
+ *
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ * _condition condition that need to be checked
+ */
+#define FOR_EACH_PORT_IF(_i, _port, _condition) FOR_EACH_PORT((_i), (_port)) \
+ if (!!(_condition))
+
+/* Macro for iterating over every port that is currently a slave of a bonded
+ * device.
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ * */
+#define FOR_EACH_SLAVE(_i, _slave) \
+ FOR_EACH_PORT_IF(_i, _slave, (_slave)->bonded != 0)
+
+/*
+ * Returns packets from slaves TX queue.
+ * slave slave port
+ * buffer for packets
+ * size size of buffer
+ * return number of packets or negative error number
+ */
+static int
+slave_get_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_ring_dequeue_burst(slave->tx_queue, (void **)buf, size);
+}
+
+/*
+ * Injects given packets into slaves RX queue.
+ * slave slave port
+ * buffer for packets
+ * size number of packets to be injected
+ * return number of queued packets or negative error number
+ */
+static int
+slave_put_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_ring_enqueue_burst(slave->rx_queue, (void **)buf, size);
+}
+
+static uint16_t
+bond_rx(struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_eth_rx_burst(test_params.bonded_port_id, 0, buf, size);
+}
+
+static uint16_t
+bond_tx(struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_eth_tx_burst(test_params.bonded_port_id, 0, buf, size);
+}
+
+static void
+free_pkts(struct rte_mbuf **pkts, uint16_t count)
+{
+ uint16_t i;
+
+ for (i = 0; i < count; i++) {
+ if (pkts[i] != NULL)
+ rte_pktmbuf_free(pkts[i]);
+ }
+}
+
+static int
+configure_ethdev(uint8_t port_id, uint8_t start)
+{
+ TEST_ASSERT(rte_eth_dev_configure(port_id, 1, 1, &default_pmd_conf) == 0,
+ "Failed to configure device %u", port_id);
+
+ TEST_ASSERT(rte_eth_rx_queue_setup(port_id, 0, RX_RING_SIZE,
+ rte_eth_dev_socket_id(port_id), NULL, test_params.mbuf_pool) == 0,
+ "Failed to setup rx queue.");
+
+ TEST_ASSERT(rte_eth_tx_queue_setup(port_id, 0, TX_RING_SIZE,
+ rte_eth_dev_socket_id(port_id), NULL) == 0,
+ "Failed to setup tx queue.");
+
+ if (start) {
+ TEST_ASSERT(rte_eth_dev_start(port_id) == 0,
+ "Failed to start device (%d).", port_id);
+ }
+ return 0;
+}
+
+static int
+add_slave(struct slave_conf *slave, uint8_t start)
+{
+ struct ether_addr addr, addr_check;
+
+ /* Some sanity check */
+ RTE_VERIFY(test_params.slave_ports <= slave &&
+ slave - test_params.slave_ports < (int)RTE_DIM(test_params.slave_ports));
+ RTE_VERIFY(slave->bonded == 0);
+ RTE_VERIFY(slave->port_id != INVALID_PORT_ID);
+
+ ether_addr_copy(&slave_mac_default, &addr);
+ addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+
+ rte_eth_dev_mac_addr_remove(slave->port_id, &addr);
+
+ TEST_ASSERT_SUCCESS(rte_eth_dev_mac_addr_add(slave->port_id, &addr, 0),
+ "Failed to set slave MAC address");
+
+ TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bonded_port_id,
+ slave->port_id),
+ "Failed to add slave (idx=%u, id=%u) to bonding (id=%u)",
+ (uint8_t)(slave - test_params.slave_ports), slave->port_id,
+ test_params.bonded_port_id);
+
+ slave->bonded = 1;
+ if (start) {
+ TEST_ASSERT_SUCCESS(rte_eth_dev_start(slave->port_id),
+ "Failed to start slave %u", slave->port_id);
+ }
+
+ rte_eth_macaddr_get(slave->port_id, &addr_check);
+ TEST_ASSERT_EQUAL(is_same_ether_addr(&addr, &addr_check), 1,
+ "Slave MAC address is not as expected");
+
+ RTE_VERIFY(slave->lacp_parnter_state == 0);
+ return 0;
+}
+
+static int
+remove_slave(struct slave_conf *slave)
+{
+ ptrdiff_t slave_idx = slave - test_params.slave_ports;
+
+ RTE_VERIFY(test_params.slave_ports <= slave &&
+ slave_idx < (ptrdiff_t)RTE_DIM(test_params.slave_ports));
+
+ RTE_VERIFY(slave->bonded == 1);
+ RTE_VERIFY(slave->port_id != INVALID_PORT_ID);
+
+ TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0,
+ "Slave %u tx queue not empty while removing from bonding.",
+ slave->port_id);
+
+ TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0,
+ "Slave %u tx queue not empty while removing from bonding.",
+ slave->port_id);
+
+ TEST_ASSERT_EQUAL(rte_eth_bond_slave_remove(test_params.bonded_port_id,
+ slave->port_id), 0,
+ "Failed to remove slave (idx=%u, id=%u) from bonding (id=%u)",
+ (uint8_t)slave_idx, slave->port_id,
+ test_params.bonded_port_id);
+
+ slave->bonded = 0;
+ slave->lacp_parnter_state = 0;
+ return 0;
+}
+
+static int
+initialize_bonded_device_with_slaves(uint8_t slave_count, uint8_t start)
+{
+ uint8_t i;
+
+ RTE_VERIFY(test_params.bonded_port_id != INVALID_PORT_ID);
+
+ for (i = 0; i < slave_count; i++) {
+ TEST_ASSERT_SUCCESS(add_slave(&test_params.slave_ports[i], 1),
+ "Failed to add port %u to bonded device.\n",
+ test_params.slave_ports[i].port_id);
+ }
+
+ /* Reset mode 4 configuration */
+ rte_eth_bond_8023ad_setup(test_params.bonded_port_id, NULL);
+ rte_eth_promiscuous_disable(test_params.bonded_port_id);
+
+ if (start)
+ TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bonded_port_id),
+ "Failed to start bonded device");
+
+ return TEST_SUCCESS;
+}
+
+static int
+remove_slaves_and_stop_bonded_device(void)
+{
+ struct slave_conf *slave;
+ int retval;
+ uint8_t slaves[RTE_MAX_ETHPORTS];
+ uint8_t i;
+
+ rte_eth_dev_stop(test_params.bonded_port_id);
+
+ FOR_EACH_SLAVE(i, slave)
+ remove_slave(slave);
+
+ retval = rte_eth_bond_slaves_get(test_params.bonded_port_id, slaves,
+ RTE_DIM(slaves));
+
+ TEST_ASSERT_EQUAL(retval, 0,
+ "Expected bonded device %u have 0 slaves but returned %d.",
+ test_params.bonded_port_id, retval);
+
+ FOR_EACH_PORT(i, slave) {
+ rte_eth_dev_stop(slave->port_id);
+
+ TEST_ASSERT(slave->bonded == 0,
+ "Port id=%u is still marked as enslaved.", slave->port_id);
+ }
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_setup(void)
+{
+ int retval, nb_mbuf_per_pool;
+ char name[RTE_ETH_NAME_MAX_LEN];
+ struct slave_conf *port;
+ const uint8_t socket_id = rte_socket_id();
+ uint8_t i;
+
+ if (test_params.mbuf_pool == NULL) {
+ nb_mbuf_per_pool = TEST_RX_DESC_MAX + DEF_PKT_BURST +
+ TEST_TX_DESC_MAX + MAX_PKT_BURST;
+ test_params.mbuf_pool = rte_mempool_create("TEST_MODE4",
+ nb_mbuf_per_pool, MBUF_SIZE, MBUF_CACHE_SIZE,
+ sizeof(struct rte_pktmbuf_pool_private),
+ rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
+ socket_id, 0);
+
+ TEST_ASSERT(test_params.mbuf_pool != NULL,
+ "rte_mempool_create failed\n");
+ }
+
+ /* Create / initialize ring eth devs. */
+ FOR_EACH_PORT(i, port) {
+ port = &test_params.slave_ports[i];
+
+ if (port->rx_queue == NULL) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_RX_QUEUE_FMT, i);
+ TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long");
+ port->rx_queue = rte_ring_create(name, RX_RING_SIZE, socket_id, 0);
+ TEST_ASSERT(port->rx_queue != NULL,
+ "Failed to allocate rx ring '%s': %s", name,
+ rte_strerror(rte_errno));
+ }
+
+ if (port->tx_queue == NULL) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_TX_QUEUE_FMT, i);
+ TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long");
+ port->tx_queue = rte_ring_create(name, TX_RING_SIZE, socket_id, 0);
+ TEST_ASSERT_NOT_NULL(port->tx_queue,
+ "Failed to allocate tx ring '%s': %s", name,
+ rte_strerror(rte_errno));
+ }
+
+ if (port->port_id == INVALID_PORT_ID) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_DEV_NAME_FMT, i);
+ TEST_ASSERT(retval < (int)RTE_DIM(name) - 1, "Name too long");
+ retval = rte_eth_from_rings(name, &port->rx_queue, 1,
+ &port->tx_queue, 1, socket_id);
+ TEST_ASSERT(retval >= 0,
+ "Failed to create ring ethdev '%s'\n", name);
+
+ port->port_id = rte_eth_dev_count() - 1;
+ }
+
+ retval = configure_ethdev(port->port_id, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to configure virtual ethdev %s\n",
+ name);
+ }
+
+ if (test_params.bonded_port_id == INVALID_PORT_ID) {
+ retval = rte_eth_bond_create(BONDED_DEV_NAME, BONDING_MODE_8023AD,
+ socket_id);
+
+ TEST_ASSERT(retval >= 0, "Failed to create bonded ethdev %s",
+ BONDED_DEV_NAME);
+
+ test_params.bonded_port_id = retval;
+ TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bonded_port_id, 0),
+ "Failed to configure bonded ethdev %s", BONDED_DEV_NAME);
+ } else if (rte_eth_bond_mode_get(test_params.bonded_port_id) !=
+ BONDING_MODE_8023AD) {
+ TEST_ASSERT(rte_eth_bond_mode_set(test_params.bonded_port_id,
+ BONDING_MODE_8023AD) == 0,
+ "Failed to set ethdev %d to mode %d",
+ test_params.bonded_port_id, BONDING_MODE_8023AD);
+ }
+
+ return 0;
+}
+
+static int
+testsuite_teardown(void)
+{
+ struct slave_conf *port;
+ uint8_t i;
+
+ /* Only stop ports.
+ * Any cleanup/reset state is done when particular test is
+ * started. */
+
+ rte_eth_dev_stop(test_params.bonded_port_id);
+
+ FOR_EACH_PORT(i, port)
+ rte_eth_dev_stop(port->port_id);
+
+ return 0;
+}
+
+/*
+ * Check if given LACP packet. If it is, make make replay packet to force
+ * COLLECTING state.
+ * return 0 when pkt is LACP frame, 1 if it is not slow frame, 2 if it is slow
+ * frame but not LACP
+ */
+static int
+make_lacp_reply(struct slave_conf *slave, struct rte_mbuf *pkt)
+{
+ struct ether_hdr *hdr;
+ struct slow_protocol_frame *slow_hdr;
+ struct lacpdu *lacp;
+
+ /* look for LACP */
+ hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ if (hdr->ether_type != rte_cpu_to_be_16(ETHER_TYPE_SLOW))
+ return 1;
+
+ slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *);
+ /* ignore packets of other types */
+ if (slow_hdr->slow_protocol.subtype != SLOW_SUBTYPE_LACP)
+ return 2;
+
+ slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *);
+
+ /* Change source address to partner address */
+ ether_addr_copy(&parnter_mac_default, &slow_hdr->eth_hdr.s_addr);
+ slow_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+
+ lacp = (struct lacpdu *) &slow_hdr->slow_protocol;
+ /* Save last received state */
+ slave->lacp_parnter_state = lacp->actor.state;
+ /* Change it into LACP replay by matching parameters. */
+ memcpy(&lacp->partner.port_params, &lacp->actor.port_params,
+ sizeof(struct port_params));
+
+ lacp->partner.state = lacp->actor.state;
+
+ ether_addr_copy(&parnter_system, &lacp->actor.port_params.system);
+ lacp->actor.state = STATE_LACP_ACTIVE |
+ STATE_SYNCHRONIZATION |
+ STATE_AGGREGATION |
+ STATE_COLLECTING |
+ STATE_DISTRIBUTING;
+
+ return 0;
+}
+
+/*
+ * Reads packets from given slave, search for LACP packet and reply them.
+ *
+ * Receives burst of packets from slave. Looks for LACP packet. Drops
+ * all other packets. Prepares response LACP and sends it back.
+ *
+ * return number of LACP received and replied, -1 on error.
+ */
+static int
+bond_handshake_reply(struct slave_conf *slave)
+{
+ int retval;
+ struct rte_mbuf *rx_buf[MAX_PKT_BURST];
+ struct rte_mbuf *lacp_tx_buf[MAX_PKT_BURST];
+ uint16_t lacp_tx_buf_cnt = 0, i;
+
+ retval = slave_get_pkts(slave, rx_buf, RTE_DIM(rx_buf));
+ TEST_ASSERT(retval >= 0, "Getting slave %u packets failed.",
+ slave->port_id);
+
+ for (i = 0; i < (uint16_t)retval; i++) {
+ if (make_lacp_reply(slave, rx_buf[i]) == 0) {
+ /* reply with actor's LACP */
+ lacp_tx_buf[lacp_tx_buf_cnt++] = rx_buf[i];
+ } else
+ rte_pktmbuf_free(rx_buf[i]);
+ }
+
+ if (lacp_tx_buf_cnt == 0)
+ return 0;
+
+ retval = slave_put_pkts(slave, lacp_tx_buf, lacp_tx_buf_cnt);
+ if (retval <= lacp_tx_buf_cnt) {
+ /* retval might be negative */
+ for (i = RTE_MAX(0, retval); retval < lacp_tx_buf_cnt; retval++)
+ rte_pktmbuf_free(lacp_tx_buf[i]);
+ }
+
+ TEST_ASSERT_EQUAL(retval, lacp_tx_buf_cnt,
+ "Failed to equeue lacp packets into slave %u tx queue.",
+ slave->port_id);
+
+ return lacp_tx_buf_cnt;
+}
+
+/*
+ * Function check if given slave tx queue contains packets that make mode 4
+ * handshake complete. It will drain slave queue.
+ * return 0 if handshake not completed, 1 if handshake was complete,
+ */
+static int
+bond_handshake_done(struct slave_conf *slave)
+{
+ const uint8_t expected_state = STATE_LACP_ACTIVE | STATE_SYNCHRONIZATION |
+ STATE_AGGREGATION | STATE_COLLECTING | STATE_DISTRIBUTING;
+
+ return slave->lacp_parnter_state == expected_state;
+}
+
+static unsigned
+bond_get_update_timeout_ms(void)
+{
+ struct rte_eth_bond_8023ad_conf conf;
+
+ rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf);
+ return conf.update_timeout_ms;
+}
+
+/*
+ * Exchanges LACP packets with partner to achieve dynamic port configuration.
+ * return TEST_SUCCESS if initial handshake succeed, TEST_FAILED otherwise.
+ */
+static int
+bond_handshake(void)
+{
+ struct slave_conf *slave;
+ struct rte_mbuf *buf[MAX_PKT_BURST];
+ uint16_t nb_pkts;
+ uint8_t all_slaves_done, i, j;
+ uint8_t status[RTE_DIM(test_params.slave_ports)] = { 0 };
+ const unsigned delay = bond_get_update_timeout_ms();
+
+ /* Exchange LACP frames */
+ all_slaves_done = 0;
+ for (i = 0; i < 30 && all_slaves_done == 0; ++i) {
+ rte_delay_ms(delay);
+
+ all_slaves_done = 1;
+ FOR_EACH_SLAVE(j, slave) {
+ /* If response already send, skip slave */
+ if (status[j] != 0)
+ continue;
+
+ if (bond_handshake_reply(slave) < 0) {
+ all_slaves_done = 0;
+ break;
+ }
+
+ status[j] = bond_handshake_done(slave);
+ if (status[j] == 0)
+ all_slaves_done = 0;
+ }
+
+ nb_pkts = bond_tx(NULL, 0);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets transmitted unexpectedly");
+
+ nb_pkts = bond_rx(buf, RTE_DIM(buf));
+ free_pkts(buf, nb_pkts);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets received unexpectedly");
+ }
+ /* If response didn't send - report failure */
+ TEST_ASSERT_EQUAL(all_slaves_done, 1, "Bond handshake failed\n");
+
+ /* If flags doesn't match - report failure */
+ return all_slaves_done = 1 ? TEST_SUCCESS : TEST_FAILED;
+}
+
+#define TEST_LACP_SLAVE_COUT RTE_DIM(test_params.slave_ports)
+static int
+test_mode4_lacp(void)
+{
+ int retval;
+
+ retval = initialize_bonded_device_with_slaves(TEST_LACP_SLAVE_COUT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ /* Test LACP handshake function */
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+generate_packets(struct ether_addr *src_mac,
+ struct ether_addr *dst_mac, uint16_t count, struct rte_mbuf **buf)
+{
+ uint16_t pktlen = PACKET_BURST_GEN_PKT_LEN;
+ uint8_t vlan_enable = 0;
+ uint16_t vlan_id = 0;
+ uint8_t ip4_type = 1; /* 0 - ipv6 */
+
+ uint16_t src_port = 10, dst_port = 20;
+
+ uint32_t ip_src[4] = { [0 ... 2] = 0xDEADBEEF, [3] = IPv4(192, 168, 0, 1) };
+ uint32_t ip_dst[4] = { [0 ... 2] = 0xFEEDFACE, [3] = IPv4(192, 168, 0, 2) };
+
+ struct ether_hdr pkt_eth_hdr;
+ struct udp_hdr pkt_udp_hdr;
+ union {
+ struct ipv4_hdr v4;
+ struct ipv6_hdr v6;
+ } pkt_ip_hdr;
+
+ int retval;
+
+ initialize_eth_header(&pkt_eth_hdr, src_mac, dst_mac, vlan_enable, vlan_id);
+
+ if (ip4_type)
+ initialize_ipv4_header(&pkt_ip_hdr.v4, ip_src[3], ip_dst[3], pktlen);
+ else
+ initialize_ipv6_header(&pkt_ip_hdr.v6, (uint8_t *)ip_src,
+ (uint8_t *)&ip_dst, pktlen);
+
+ initialize_udp_header(&pkt_udp_hdr, src_port, dst_port, 16);
+
+ retval = generate_packet_burst(test_params.mbuf_pool, buf,
+ &pkt_eth_hdr, vlan_enable, &pkt_ip_hdr, 1, &pkt_udp_hdr,
+ count, pktlen, 1);
+
+ if (retval > 0 && retval != count)
+ free_pkts(&buf[count - retval], retval);
+
+ TEST_ASSERT_EQUAL(retval, count, "Failed to generate %u packets",
+ count);
+
+ return count;
+}
+
+static int
+generate_and_put_packets(struct slave_conf *slave, struct ether_addr *src_mac,
+ struct ether_addr *dst_mac, uint16_t count)
+{
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+
+ retval = generate_packets(src_mac, dst_mac, count, pkts);
+ if (retval != (int)count)
+ return retval;
+
+ retval = slave_put_pkts(slave, pkts, count);
+ if (retval > 0 && retval != count)
+ free_pkts(&pkts[retval], count - retval);
+
+ TEST_ASSERT_EQUAL(retval, count,
+ "Failed to enqueue packets into slave %u RX queue", slave->port_id);
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_rx(void)
+{
+ struct slave_conf *slave;
+ uint16_t i, j;
+
+ uint16_t expected_pkts_cnt;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+ unsigned delay;
+
+ struct ether_hdr *hdr;
+
+ struct ether_addr src_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } };
+ struct ether_addr dst_mac;
+ struct ether_addr bonded_mac;
+
+ retval = initialize_bonded_device_with_slaves(TEST_PROMISC_SLAVE_COUNT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac);
+ ether_addr_copy(&bonded_mac, &dst_mac);
+
+ /* Assert that dst address is not bonding address */
+ dst_mac.addr_bytes[0]++;
+
+ /* First try with promiscuous mode enabled.
+ * Add 2 packets to each slave. First with bonding MAC address, second with
+ * different. Check if we received all of them. */
+ rte_eth_promiscuous_enable(test_params.bonded_port_id);
+
+ expected_pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ /* Expect 2 packets per slave */
+ expected_pkts_cnt += 2;
+ }
+
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval == expected_pkts_cnt) {
+ int cnt[2] = { 0, 0 };
+
+ for (i = 0; i < expected_pkts_cnt; i++) {
+ hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+ cnt[is_same_ether_addr(&hdr->d_addr, &bonded_mac)]++;
+ }
+
+ free_pkts(pkts, expected_pkts_cnt);
+
+ /* For division by 2 expected_pkts_cnt must be even */
+ RTE_VERIFY((expected_pkts_cnt & 1) == 0);
+ TEST_ASSERT(cnt[0] == expected_pkts_cnt / 2 &&
+ cnt[1] == expected_pkts_cnt / 2,
+ "Expected %u packets with the same MAC and %u with different but "
+ "got %u with the same and %u with diffrent MAC",
+ expected_pkts_cnt / 2, expected_pkts_cnt / 2, cnt[1], cnt[0]);
+ } else if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, expected_pkts_cnt,
+ "Expected %u packets but received only %d", expected_pkts_cnt, retval);
+
+ /* Now, disable promiscuous mode. When promiscuous mode is disabled we
+ * expect to receive only packets that are directed to bonding port. */
+ rte_eth_promiscuous_disable(test_params.bonded_port_id);
+
+ expected_pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ /* Expect only one packet per slave */
+ expected_pkts_cnt += 1;
+ }
+
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval == expected_pkts_cnt) {
+ int eq_cnt = 0;
+
+ for (i = 0; i < expected_pkts_cnt; i++) {
+ hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+ eq_cnt += is_same_ether_addr(&hdr->d_addr, &bonded_mac);
+ }
+
+ free_pkts(pkts, expected_pkts_cnt);
+ TEST_ASSERT_EQUAL(eq_cnt, expected_pkts_cnt, "Packet address mismatch");
+ } else if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, expected_pkts_cnt,
+ "Expected %u packets but received only %d", expected_pkts_cnt, retval);
+
+ /* Link down test: simulate link down for first slave. */
+ delay = bond_get_update_timeout_ms();
+
+ uint8_t slave_down_id = INVALID_PORT_ID;
+
+ /* Find first slave and make link down on it*/
+ FOR_EACH_SLAVE(i, slave) {
+ rte_eth_dev_set_link_down(slave->port_id);
+ slave_down_id = slave->port_id;
+ break;
+ }
+
+ RTE_VERIFY(slave_down_id != INVALID_PORT_ID);
+
+ /* Give some time to rearrange bonding */
+ for (i = 0; i < 3; i++) {
+ rte_delay_ms(delay);
+ bond_handshake();
+ }
+
+ TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed");
+
+ /* Put packet to each slave */
+ FOR_EACH_SLAVE(i, slave) {
+ void *pkt = NULL;
+
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst.");
+
+ src_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst.");
+
+ retval = bond_rx(pkts, RTE_DIM(pkts));
+
+ /* Clean anything */
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ while (rte_ring_dequeue(slave->rx_queue, (void **)&pkt) == 0)
+ rte_pktmbuf_free(pkt);
+
+ if (slave_down_id == slave->port_id)
+ TEST_ASSERT_EQUAL(retval, 0, "Packets received unexpectedly.");
+ else
+ TEST_ASSERT_NOT_EQUAL(retval, 0,
+ "Expected to receive some packets on slave %u.",
+ slave->port_id);
+ rte_eth_dev_start(slave->port_id);
+
+ for (j = 0; j < 5; j++) {
+ TEST_ASSERT(bond_handshake_reply(slave) >= 0,
+ "Handshake after link up");
+
+ if (bond_handshake_done(slave) == 1)
+ break;
+ }
+
+ TEST_ASSERT(j < 5, "Failed to agregate slave after link up");
+ }
+
+ remove_slaves_and_stop_bonded_device();
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_tx_burst(void)
+{
+ struct slave_conf *slave;
+ uint16_t i, j;
+
+ uint16_t exp_pkts_cnt, pkts_cnt = 0;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+ unsigned delay;
+
+ struct ether_addr dst_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } };
+ struct ether_addr bonded_mac;
+
+ retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac);
+
+ /* Prepare burst */
+ for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) {
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt;
+ retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]);
+
+ if (retval != 1)
+ free_pkts(pkts, pkts_cnt);
+
+ TEST_ASSERT_EQUAL(retval, 1, "Failed to generate packet %u", pkts_cnt);
+ }
+ exp_pkts_cnt = pkts_cnt;
+
+ /* Transmit packets on bonded device */
+ retval = bond_tx(pkts, pkts_cnt);
+ if (retval > 0 && retval < pkts_cnt)
+ free_pkts(&pkts[retval], pkts_cnt - retval);
+
+ TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed");
+
+ /* Check if packets were transmitted properly. Every slave should have
+ * at least one packet, and sum must match. Under normal operation
+ * there should be no LACP nor MARKER frames. */
+ pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ uint16_t normal_cnt, slow_cnt;
+
+ retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts));
+ normal_cnt = 0;
+ slow_cnt = 0;
+
+ for (j = 0; j < retval; j++) {
+ if (make_lacp_reply(slave, pkts[j]) == 1)
+ normal_cnt++;
+ else
+ slow_cnt++;
+ }
+
+ free_pkts(pkts, normal_cnt + slow_cnt);
+ TEST_ASSERT_EQUAL(slow_cnt, 0,
+ "slave %u unexpectedly transmitted %d SLOW packets", slave->port_id,
+ slow_cnt);
+
+ TEST_ASSERT_NOT_EQUAL(normal_cnt, 0,
+ "slave %u did not transmitted any packets", slave->port_id);
+
+ pkts_cnt += normal_cnt;
+ }
+
+ TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt,
+ "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt);
+
+ /* Link down test:
+ * simulate link down for first slave. */
+ delay = bond_get_update_timeout_ms();
+
+ uint8_t slave_down_id = INVALID_PORT_ID;
+
+ FOR_EACH_SLAVE(i, slave) {
+ rte_eth_dev_set_link_down(slave->port_id);
+ slave_down_id = slave->port_id;
+ break;
+ }
+
+ RTE_VERIFY(slave_down_id != INVALID_PORT_ID);
+
+ /* Give some time to rearrange bonding. */
+ for (i = 0; i < 3; i++) {
+ bond_handshake();
+ rte_delay_ms(delay);
+ }
+
+ TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed");
+
+ /* Prepare burst. */
+ for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) {
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt;
+ retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]);
+
+ if (retval != 1)
+ free_pkts(pkts, pkts_cnt);
+
+ TEST_ASSERT_EQUAL(retval, 1, "Failed to generate test packet %u",
+ pkts_cnt);
+ }
+ exp_pkts_cnt = pkts_cnt;
+
+ /* Transmit packets on bonded device. */
+ retval = bond_tx(pkts, pkts_cnt);
+ if (retval > 0 && retval < pkts_cnt)
+ free_pkts(&pkts[retval], pkts_cnt - retval);
+
+ TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed");
+
+ /* Check if packets was transmitted properly. Every slave should have
+ * at least one packet, and sum must match. Under normal operation
+ * there should be no LACP nor MARKER frames. */
+ pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ uint16_t normal_cnt, slow_cnt;
+
+ retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts));
+ normal_cnt = 0;
+ slow_cnt = 0;
+
+ for (j = 0; j < retval; j++) {
+ if (make_lacp_reply(slave, pkts[j]) == 1)
+ normal_cnt++;
+ else
+ slow_cnt++;
+ }
+
+ free_pkts(pkts, normal_cnt + slow_cnt);
+
+ if (slave_down_id == slave->port_id) {
+ TEST_ASSERT_EQUAL(normal_cnt + slow_cnt, 0,
+ "slave %u enexpectedly transmitted %u packets",
+ normal_cnt + slow_cnt, slave->port_id);
+ } else {
+ TEST_ASSERT_EQUAL(slow_cnt, 0,
+ "slave %u unexpectedly transmitted %d SLOW packets",
+ slave->port_id, slow_cnt);
+
+ TEST_ASSERT_NOT_EQUAL(normal_cnt, 0,
+ "slave %u did not transmitted any packets", slave->port_id);
+ }
+
+ pkts_cnt += normal_cnt;
+ }
+
+ TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt,
+ "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt);
+
+ return remove_slaves_and_stop_bonded_device();
+}
+
+static void
+init_marker(struct rte_mbuf *pkt, struct slave_conf *slave)
+{
+ struct marker_header *marker_hdr = rte_pktmbuf_mtod(pkt,
+ struct marker_header *);
+
+ /* Copy multicast destination address */
+ ether_addr_copy(&slow_protocol_mac_addr, &marker_hdr->eth_hdr.d_addr);
+
+ /* Init source address */
+ ether_addr_copy(&parnter_mac_default, &marker_hdr->eth_hdr.s_addr);
+ marker_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN-1] = slave->port_id;
+
+ marker_hdr->eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_SLOW);
+
+ marker_hdr->marker.subtype = SLOW_SUBTYPE_MARKER;
+ marker_hdr->marker.version_number = 1;
+ marker_hdr->marker.tlv_type_marker = MARKER_TLV_TYPE_INFO;
+ marker_hdr->marker.info_length =
+ offsetof(struct marker, reserved_90) -
+ offsetof(struct marker, requester_port);
+ RTE_VERIFY(marker_hdr->marker.info_length == 16);
+ marker_hdr->marker.requester_port = slave->port_id + 1;
+ marker_hdr->marker.tlv_type_terminator = TLV_TYPE_TERMINATOR_INFORMATION;
+ marker_hdr->marker.terminator_length = 0;
+}
+
+static int
+test_mode4_marker(void)
+{
+ struct slave_conf *slave;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ struct rte_mbuf *marker_pkt;
+ struct marker_header *marker_hdr;
+
+ unsigned delay;
+ int retval;
+ uint16_t nb_pkts;
+ uint8_t i, j;
+ const uint16_t ethtype_slow_be = rte_be_to_cpu_16(ETHER_TYPE_SLOW);
+
+ retval = initialize_bonded_device_with_slaves(TEST_MARKER_SLAVE_COUT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ /* Test LACP handshake function */
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ delay = bond_get_update_timeout_ms();
+ FOR_EACH_SLAVE(i, slave) {
+ marker_pkt = rte_pktmbuf_alloc(test_params.mbuf_pool);
+ TEST_ASSERT_NOT_NULL(marker_pkt, "Failed to allocate marker packet");
+ init_marker(marker_pkt, slave);
+
+ retval = slave_put_pkts(slave, &marker_pkt, 1);
+ if (retval != 1)
+ rte_pktmbuf_free(marker_pkt);
+
+ TEST_ASSERT_EQUAL(retval, 1,
+ "Failed to send marker packet to slave %u", slave->port_id);
+
+ for (j = 0; j < 20; ++j) {
+ rte_delay_ms(delay);
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 0, "Received packets unexpectedly");
+
+ retval = rte_eth_tx_burst(test_params.bonded_port_id, 0, NULL, 0);
+ TEST_ASSERT_EQUAL(retval, 0,
+ "Requested TX of 0 packets but %d transmitted", retval);
+
+ /* Check if LACP packet was send by state machines
+ First and only packet must be a maker response */
+ retval = slave_get_pkts(slave, pkts, MAX_PKT_BURST);
+ if (retval == 0)
+ continue;
+ if (retval > 1)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 1, "failed to get slave packets");
+ nb_pkts = retval;
+
+ marker_hdr = rte_pktmbuf_mtod(pkts[0], struct marker_header *);
+ /* Check if it's slow packet*/
+ if (marker_hdr->eth_hdr.ether_type != ethtype_slow_be)
+ retval = -1;
+ /* Check if it's marker packet */
+ else if (marker_hdr->marker.subtype != SLOW_SUBTYPE_MARKER)
+ retval = -2;
+ else if (marker_hdr->marker.tlv_type_marker != MARKER_TLV_TYPE_RESP)
+ retval = -3;
+
+ free_pkts(pkts, nb_pkts);
+
+ TEST_ASSERT_NOT_EQUAL(retval, -1, "Unexpected protocol type");
+ TEST_ASSERT_NOT_EQUAL(retval, -2, "Unexpected sub protocol type");
+ TEST_ASSERT_NOT_EQUAL(retval, -3, "Unexpected marker type");
+ break;
+ }
+
+ TEST_ASSERT(j < 20, "Marker response not found");
+ }
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_expired(void)
+{
+ struct slave_conf *slave, *exp_slave = NULL;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ struct rte_mbuf *pkt = NULL;
+ int retval;
+ uint32_t old_delay;
+
+ uint8_t i;
+ uint16_t j;
+
+ struct rte_eth_bond_8023ad_conf conf;
+
+ retval = initialize_bonded_device_with_slaves(TEST_EXPIRED_SLAVE_COUNT, 1);
+ /* Set custom timeouts to make test last shorter. */
+ rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf);
+ conf.fast_periodic_ms = 100;
+ conf.slow_periodic_ms = 600;
+ conf.short_timeout_ms = 300;
+ conf.long_timeout_ms = 900;
+ conf.aggregate_wait_timeout_ms = 200;
+ conf.tx_period_ms = 100;
+ old_delay = conf.update_timeout_ms;
+ conf.update_timeout_ms = 10;
+ rte_eth_bond_8023ad_setup(test_params.bonded_port_id, &conf);
+
+ /* Wait for new settings to be applied. */
+ for (i = 0; i < old_delay/conf.update_timeout_ms * 2; i++) {
+ FOR_EACH_SLAVE(j, slave)
+ bond_handshake_reply(slave);
+
+ rte_delay_ms(conf.update_timeout_ms);
+ }
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ /* Find first slave */
+ FOR_EACH_SLAVE(i, slave) {
+ exp_slave = slave;
+ break;
+ }
+
+ RTE_VERIFY(exp_slave != NULL);
+
+ /* When one of partners do not send or respond to LACP frame in
+ * conf.long_timeout_ms time, internal state machines should detect this
+ * and transit to expired state. */
+ for (j = 0; j < conf.long_timeout_ms/conf.update_timeout_ms + 2; j++) {
+ rte_delay_ms(conf.update_timeout_ms);
+
+ retval = bond_tx(NULL, 0);
+ TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets",
+ retval);
+
+ FOR_EACH_SLAVE(i, slave) {
+ retval = bond_handshake_reply(slave);
+ TEST_ASSERT(retval >= 0, "Handshake failed");
+
+ /* Remove replay for slave that supose to be expired. */
+ if (slave == exp_slave) {
+ while (rte_ring_count(slave->rx_queue) > 0) {
+ rte_ring_dequeue(slave->rx_queue, (void **)&pkt);
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+
+ retval = bond_rx(pkts, RTE_DIM(pkts));
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets",
+ retval);
+ }
+
+ /* After test only expected slave should be in EXPIRED state */
+ FOR_EACH_SLAVE(i, slave) {
+ if (slave == exp_slave)
+ TEST_ASSERT(slave->lacp_parnter_state & STATE_EXPIRED,
+ "Slave %u should be in expired.", slave->port_id);
+ else
+ TEST_ASSERT_EQUAL(bond_handshake_done(slave), 1,
+ "Slave %u should be operational.", slave->port_id);
+ }
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+check_environment(void)
+{
+ struct slave_conf *port;
+ uint8_t i, env_state;
+ uint8_t slaves[RTE_DIM(test_params.slave_ports)];
+ int slaves_count;
+
+ env_state = 0;
+ FOR_EACH_PORT(i, port) {
+ if (rte_ring_count(port->rx_queue) != 0)
+ env_state |= 0x01;
+
+ if (rte_ring_count(port->tx_queue) != 0)
+ env_state |= 0x02;
+
+ if (port->bonded != 0)
+ env_state |= 0x04;
+
+ if (port->lacp_parnter_state != 0)
+ env_state |= 0x08;
+
+ if (env_state != 0)
+ break;
+ }
+
+ slaves_count = rte_eth_bond_slaves_get(test_params.bonded_port_id,
+ slaves, RTE_DIM(slaves));
+
+ if (slaves_count != 0)
+ env_state |= 0x10;
+
+ TEST_ASSERT_EQUAL(env_state, 0,
+ "Environment not clean (port %u):%s%s%s%s%s",
+ port->port_id,
+ env_state & 0x01 ? " slave rx queue not clean" : "",
+ env_state & 0x02 ? " slave tx queue not clean" : "",
+ env_state & 0x04 ? " port marked as enslaved" : "",
+ env_state & 0x80 ? " slave state is not reset" : "",
+ env_state & 0x10 ? " slave count not equal 0" : ".");
+
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_executor(int (*test_func)(void))
+{
+ struct slave_conf *port;
+ int test_result;
+ uint8_t i;
+ void *pkt;
+
+ /* Check if environment is clean. Fail to launch a test if there was
+ * a critical error before that prevented to reset environment. */
+ TEST_ASSERT_SUCCESS(check_environment(),
+ "Refusing to launch test in dirty environment.");
+
+ RTE_VERIFY(test_func != NULL);
+ test_result = (*test_func)();
+
+ /* If test succeed check if environment wast left in good condition. */
+ if (test_result == TEST_SUCCESS)
+ test_result = check_environment();
+
+ /* Reset environment in case test failed to do that. */
+ if (test_result != TEST_SUCCESS) {
+ TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(),
+ "Failed to stop bonded device");
+
+ FOR_EACH_PORT(i, port) {
+ while (rte_ring_count(port->rx_queue) != 0) {
+ if (rte_ring_dequeue(port->rx_queue, &pkt) == 0)
+ rte_pktmbuf_free(pkt);
+ }
+
+ while (rte_ring_count(port->tx_queue) != 0) {
+ if (rte_ring_dequeue(port->tx_queue, &pkt) == 0)
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+
+ return test_result;
+}
+
+static int
+test_mode4_lacp_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_lacp);
+}
+
+static int
+test_mode4_marker_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_marker);
+}
+
+static int
+test_mode4_rx_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_rx);
+}
+
+static int
+test_mode4_tx_burst_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_tx_burst);
+}
+
+static int
+test_mode4_expired_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_expired);
+}
+
+static struct unit_test_suite link_bonding_mode4_test_suite = {
+ .suite_name = "Link Bonding mode 4 Unit Test Suite",
+ .setup = test_setup,
+ .teardown = testsuite_teardown,
+ .unit_test_cases = {
+ TEST_CASE_NAMED("test_mode4_lacp", test_mode4_lacp_wrapper),
+ TEST_CASE_NAMED("test_mode4_rx", test_mode4_rx_wrapper),
+ TEST_CASE_NAMED("test_mode4_tx_burst", test_mode4_tx_burst_wrapper),
+ TEST_CASE_NAMED("test_mode4_marker", test_mode4_marker_wrapper),
+ TEST_CASE_NAMED("test_mode4_expired", test_mode4_expired_wrapper),
+ { NULL, NULL, NULL, NULL, NULL } /**< NULL terminate unit test array */
+ }
+};
+
+static int
+test_link_bonding_mode4(void)
+{
+ return unit_test_suite_runner(&link_bonding_mode4_test_suite);
+}
+
+static struct test_command link_bonding_cmd = {
+ .command = "link_bonding_mode4_autotest",
+ .callback = test_link_bonding_mode4,
+};
+
+REGISTER_TEST_COMMAND(link_bonding_cmd);
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/3] PMD ring MAC management, fix initialization, link up/down
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 0/3] " Tomasz Kulasek
` (2 preceding siblings ...)
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 3/3] PMD Ring - Fix for MAC per device management Tomasz Kulasek
@ 2015-01-28 11:56 ` Doherty, Declan
2015-02-18 17:33 ` Thomas Monjalon
3 siblings, 1 reply; 30+ messages in thread
From: Doherty, Declan @ 2015-01-28 11:56 UTC (permalink / raw)
To: Kulasek, TomaszX, dev
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Kulasek
> Sent: Monday, January 19, 2015 11:57 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v2 0/3] PMD ring MAC management, fix initialization,
> link up/down
>
> Patch split into smaller parts to separate features from previous version.
>
> Tomasz Kulasek (3):
> PMD Ring - Add link up/down functions
> PMD Ring - Add MAC addr add/remove functions
> PMD Ring - Fix for per device management
>
> lib/librte_pmd_ring/rte_eth_ring.c | 62
> +++++++++++++++++++++++++++++++++---
> 1 file changed, 57 insertions(+), 5 deletions(-)
>
> --
> 1.7.9.5
Acked-by: Declan Doherty <declan.doherty@intel.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v3 0/3] Unit tests for mode 4
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 0/2] " Tomasz Kulasek
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 1/2] Unit tests - test.h rework Tomasz Kulasek
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 2/2] Unit tests for mode 4 Tomasz Kulasek
@ 2015-01-29 8:51 ` Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 1/3] test: test.h rework Tomasz Kulasek
` (3 more replies)
2 siblings, 4 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-29 8:51 UTC (permalink / raw)
To: dev
This patch series depends of "PMD ring" patches and should be applied after them.
v3 changes
- Fix compilation issues for dynamic libraries
- Re-create a series of patches to maintain consistency
v2 changes
- Patch split for better readability
Tomasz Kulasek (3):
Unit tests - test.h rework
Unit tests for mode 4
mk: Link test application against librte_pmd_ring when needed
app/test/Makefile | 16 +
app/test/test.h | 112 +--
app/test/test_link_bonding.c | 2 +-
app/test/test_link_bonding_mode4.c | 1412 ++++++++++++++++++++++++++++++++++++
4 files changed, 1495 insertions(+), 47 deletions(-)
create mode 100644 app/test/test_link_bonding_mode4.c
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v3 1/3] test: test.h rework
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 0/3] " Tomasz Kulasek
@ 2015-01-29 8:51 ` Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 2/3] test: Unit tests for mode 4 Tomasz Kulasek
` (2 subsequent siblings)
3 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-29 8:51 UTC (permalink / raw)
To: dev
v3 changes
- No major changes. Patch re-created for current release to maintain
consistency.
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
app/test/test.h | 112 ++++++++++++++++++++++++++++++++-----------------------
1 file changed, 66 insertions(+), 46 deletions(-)
diff --git a/app/test/test.h b/app/test/test.h
index 896f7db..5450986 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -36,62 +36,79 @@
#include <sys/queue.h>
-#define TEST_ASSERT(cond, msg, ...) do { \
- if (!(cond)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
-} while (0)
+#define TEST_SUCCESS (0)
+#define TEST_FAILED (-1)
+
+/* Before including test.h file you can define
+ * TEST_TRACE_FAILURE(_file, _line, _func) macro to better trace/debug test
+ * failures. Mostly useful in test development phase. */
+#ifndef TEST_TRACE_FAILURE
+# define TEST_TRACE_FAILURE(_file, _line, _func)
+#endif
-#define TEST_ASSERT_EQUAL(a, b, msg, ...) do { \
- if (!(a == b)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT(cond, msg, ...) do { \
+ if (!(cond)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_NOT_EQUAL(a, b, msg, ...) do { \
- if (!(a != b)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_EQUAL(a, b, msg, ...) do { \
+ if (!(a == b)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \
- if (!(val == 0)) { \
- printf("TestCase %s() line %d failed (err %d): " \
- msg "\n", __func__, __LINE__, val, \
- ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NOT_EQUAL(a, b, msg, ...) do { \
+ if (!(a != b)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_FAIL(val, msg, ...) do { \
- if (!(val != 0)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \
+ typeof(val) _val = (val); \
+ if (!(_val == 0)) { \
+ printf("TestCase %s() line %d failed (err %d): " \
+ msg "\n", __func__, __LINE__, _val, \
+ ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
+#define TEST_ASSERT_FAIL(val, msg, ...) do { \
+ if (!(val != 0)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
+} while (0)
-#define TEST_ASSERT_NULL(val, msg, ...) do { \
- if (!(val == NULL)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NULL(val, msg, ...) do { \
+ if (!(val == NULL)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \
- if (!(val != NULL)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \
+ if (!(val != NULL)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
struct unit_test_case {
@@ -104,8 +121,11 @@ struct unit_test_case {
#define TEST_CASE(fn) { NULL, NULL, fn, #fn " succeeded", #fn " failed"}
-#define TEST_CASE_ST(setup, teardown, testcase) \
- { setup, teardown, testcase, #testcase " succeeded", \
+#define TEST_CASE_NAMED(name, fn) { NULL, NULL, fn, name " succeeded", \
+ name " failed"}
+
+#define TEST_CASE_ST(setup, teardown, testcase) \
+ { setup, teardown, testcase, #testcase " succeeded", \
#testcase " failed "}
#define TEST_CASES_END() { NULL, NULL, NULL, NULL, NULL }
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v3 2/3] test: Unit tests for mode 4
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 0/3] " Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 1/3] test: test.h rework Tomasz Kulasek
@ 2015-01-29 8:51 ` Tomasz Kulasek
2015-02-12 11:49 ` Declan Doherty
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3] mk: Link test app against librte_pmd_ring when needed Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Tomasz Kulasek
3 siblings, 1 reply; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-29 8:51 UTC (permalink / raw)
To: dev
This patch adds unit tests for mode 4. It is split into separate
file to avoid problems with other modes that does not need to
look into packets payload.
This patch includes also a modification of maximum number of ports
used in their tests for bonding modes 0-3 from 16 to 6.
v3 changes
- Patch re-created for current release to maintain consistency
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
app/test/Makefile | 1 +
app/test/test_link_bonding.c | 2 +-
app/test/test_link_bonding_mode4.c | 1412 ++++++++++++++++++++++++++++++++++++
3 files changed, 1414 insertions(+), 1 deletion(-)
create mode 100644 app/test/test_link_bonding_mode4.c
diff --git a/app/test/Makefile b/app/test/Makefile
index 4311f96..ee0e95a 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -129,6 +129,7 @@ SRCS-y += virtual_pmd.c
SRCS-y += packet_burst_generator.c
SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding_mode4.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring.c
SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index 4523de6..6d5b383 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -57,7 +57,7 @@
#include "test.h"
-#define TEST_MAX_NUMBER_OF_PORTS (16)
+#define TEST_MAX_NUMBER_OF_PORTS (6)
#define RX_RING_SIZE 128
#define RX_FREE_THRESH 32
diff --git a/app/test/test_link_bonding_mode4.c b/app/test/test_link_bonding_mode4.c
new file mode 100644
index 0000000..f8d0955
--- /dev/null
+++ b/app/test/test_link_bonding_mode4.c
@@ -0,0 +1,1412 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <rte_cycles.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_memory.h>
+
+#include <rte_string_fns.h>
+
+#include <rte_eth_ring.h>
+#include <rte_errno.h>
+#include <rte_eth_bond.h>
+#include <rte_eth_bond_8023ad.h>
+
+#include "packet_burst_generator.h"
+
+#include "test.h"
+
+#define SLAVE_COUNT (4)
+
+#define RX_RING_SIZE 128
+#define TX_RING_SIZE 512
+
+#define MBUF_PAYLOAD_SIZE (2048)
+#define MBUF_SIZE (MBUF_PAYLOAD_SIZE + sizeof(struct rte_mbuf) + \
+ RTE_PKTMBUF_HEADROOM)
+#define MBUF_CACHE_SIZE (250)
+#define BURST_SIZE (32)
+
+#define DEFAULT_MBUF_DATA_SIZE (2048)
+#define TEST_RX_DESC_MAX (2048)
+#define TEST_TX_DESC_MAX (2048)
+#define MAX_PKT_BURST (32)
+#define DEF_PKT_BURST (16)
+
+#define BONDED_DEV_NAME ("unit_test_mode4_bond_dev")
+
+#define SLAVE_DEV_NAME_FMT ("unit_test_mode4_slave_%d")
+#define SLAVE_RX_QUEUE_FMT ("unit_test_mode4_slave_%d_rx")
+#define SLAVE_TX_QUEUE_FMT ("unit_test_mode4_slave_%d_tx")
+
+#define INVALID_SOCKET_ID (-1)
+#define INVALID_PORT_ID (0xFF)
+#define INVALID_BONDING_MODE (-1)
+
+static const struct ether_addr slave_mac_default = {
+ { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 }
+};
+
+static const struct ether_addr parnter_mac_default = {
+ { 0x22, 0xBB, 0xFF, 0xBB, 0x00, 0x00 }
+};
+
+static const struct ether_addr parnter_system = {
+ { 0x33, 0xFF, 0xBB, 0xFF, 0x00, 0x00 }
+};
+
+static const struct ether_addr slow_protocol_mac_addr = {
+ { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 }
+};
+
+struct slave_conf {
+ struct rte_ring *rx_queue;
+ struct rte_ring *tx_queue;
+ uint8_t port_id;
+ uint8_t bonded : 1;
+
+ uint8_t lacp_parnter_state;
+};
+
+struct ether_vlan_hdr {
+ struct ether_hdr pkt_eth_hdr;
+ struct vlan_hdr vlan_hdr;
+};
+
+struct link_bonding_unittest_params {
+ uint8_t bonded_port_id;
+ struct slave_conf slave_ports[SLAVE_COUNT];
+
+ struct rte_mempool *mbuf_pool;
+};
+
+#define TEST_DEFAULT_SLAVE_COUNT RTE_DIM(test_params.slave_ports)
+#define TEST_RX_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_TX_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_MARKER_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_EXPIRED_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_PROMISC_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+
+static struct link_bonding_unittest_params test_params = {
+ .bonded_port_id = INVALID_PORT_ID,
+ .slave_ports = { [0 ... SLAVE_COUNT - 1] = { .port_id = INVALID_PORT_ID} },
+
+ .mbuf_pool = NULL,
+};
+
+static struct rte_eth_conf default_pmd_conf = {
+ .rxmode = {
+ .mq_mode = ETH_MQ_RX_NONE,
+ .max_rx_pkt_len = ETHER_MAX_LEN,
+ .split_hdr_size = 0,
+ .header_split = 0, /**< Header Split disabled */
+ .hw_ip_checksum = 0, /**< IP checksum offload enabled */
+ .hw_vlan_filter = 0, /**< VLAN filtering disabled */
+ .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /**< CRC stripped by hardware */
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+ .lpbk_mode = 0,
+};
+
+#define FOR_EACH(_i, _item, _array, _size) \
+ for (_i = 0, _item = &_array[0]; _i < _size && (_item = &_array[_i]); _i++)
+
+/* Macro for iterating over every port that can be used as a slave
+ * in this test.
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ */
+#define FOR_EACH_PORT(_i, _port) \
+ FOR_EACH(_i, _port, test_params.slave_ports, \
+ RTE_DIM(test_params.slave_ports))
+
+/* Macro for iterating over every port that can be used as a slave
+ * in this test and satisfy given condition.
+ *
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ * _condition condition that need to be checked
+ */
+#define FOR_EACH_PORT_IF(_i, _port, _condition) FOR_EACH_PORT((_i), (_port)) \
+ if (!!(_condition))
+
+/* Macro for iterating over every port that is currently a slave of a bonded
+ * device.
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ * */
+#define FOR_EACH_SLAVE(_i, _slave) \
+ FOR_EACH_PORT_IF(_i, _slave, (_slave)->bonded != 0)
+
+/*
+ * Returns packets from slaves TX queue.
+ * slave slave port
+ * buffer for packets
+ * size size of buffer
+ * return number of packets or negative error number
+ */
+static int
+slave_get_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_ring_dequeue_burst(slave->tx_queue, (void **)buf, size);
+}
+
+/*
+ * Injects given packets into slaves RX queue.
+ * slave slave port
+ * buffer for packets
+ * size number of packets to be injected
+ * return number of queued packets or negative error number
+ */
+static int
+slave_put_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_ring_enqueue_burst(slave->rx_queue, (void **)buf, size);
+}
+
+static uint16_t
+bond_rx(struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_eth_rx_burst(test_params.bonded_port_id, 0, buf, size);
+}
+
+static uint16_t
+bond_tx(struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_eth_tx_burst(test_params.bonded_port_id, 0, buf, size);
+}
+
+static void
+free_pkts(struct rte_mbuf **pkts, uint16_t count)
+{
+ uint16_t i;
+
+ for (i = 0; i < count; i++) {
+ if (pkts[i] != NULL)
+ rte_pktmbuf_free(pkts[i]);
+ }
+}
+
+static int
+configure_ethdev(uint8_t port_id, uint8_t start)
+{
+ TEST_ASSERT(rte_eth_dev_configure(port_id, 1, 1, &default_pmd_conf) == 0,
+ "Failed to configure device %u", port_id);
+
+ TEST_ASSERT(rte_eth_rx_queue_setup(port_id, 0, RX_RING_SIZE,
+ rte_eth_dev_socket_id(port_id), NULL, test_params.mbuf_pool) == 0,
+ "Failed to setup rx queue.");
+
+ TEST_ASSERT(rte_eth_tx_queue_setup(port_id, 0, TX_RING_SIZE,
+ rte_eth_dev_socket_id(port_id), NULL) == 0,
+ "Failed to setup tx queue.");
+
+ if (start) {
+ TEST_ASSERT(rte_eth_dev_start(port_id) == 0,
+ "Failed to start device (%d).", port_id);
+ }
+ return 0;
+}
+
+static int
+add_slave(struct slave_conf *slave, uint8_t start)
+{
+ struct ether_addr addr, addr_check;
+
+ /* Some sanity check */
+ RTE_VERIFY(test_params.slave_ports <= slave &&
+ slave - test_params.slave_ports < (int)RTE_DIM(test_params.slave_ports));
+ RTE_VERIFY(slave->bonded == 0);
+ RTE_VERIFY(slave->port_id != INVALID_PORT_ID);
+
+ ether_addr_copy(&slave_mac_default, &addr);
+ addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+
+ rte_eth_dev_mac_addr_remove(slave->port_id, &addr);
+
+ TEST_ASSERT_SUCCESS(rte_eth_dev_mac_addr_add(slave->port_id, &addr, 0),
+ "Failed to set slave MAC address");
+
+ TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bonded_port_id,
+ slave->port_id),
+ "Failed to add slave (idx=%u, id=%u) to bonding (id=%u)",
+ (uint8_t)(slave - test_params.slave_ports), slave->port_id,
+ test_params.bonded_port_id);
+
+ slave->bonded = 1;
+ if (start) {
+ TEST_ASSERT_SUCCESS(rte_eth_dev_start(slave->port_id),
+ "Failed to start slave %u", slave->port_id);
+ }
+
+ rte_eth_macaddr_get(slave->port_id, &addr_check);
+ TEST_ASSERT_EQUAL(is_same_ether_addr(&addr, &addr_check), 1,
+ "Slave MAC address is not as expected");
+
+ RTE_VERIFY(slave->lacp_parnter_state == 0);
+ return 0;
+}
+
+static int
+remove_slave(struct slave_conf *slave)
+{
+ ptrdiff_t slave_idx = slave - test_params.slave_ports;
+
+ RTE_VERIFY(test_params.slave_ports <= slave &&
+ slave_idx < (ptrdiff_t)RTE_DIM(test_params.slave_ports));
+
+ RTE_VERIFY(slave->bonded == 1);
+ RTE_VERIFY(slave->port_id != INVALID_PORT_ID);
+
+ TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0,
+ "Slave %u tx queue not empty while removing from bonding.",
+ slave->port_id);
+
+ TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0,
+ "Slave %u tx queue not empty while removing from bonding.",
+ slave->port_id);
+
+ TEST_ASSERT_EQUAL(rte_eth_bond_slave_remove(test_params.bonded_port_id,
+ slave->port_id), 0,
+ "Failed to remove slave (idx=%u, id=%u) from bonding (id=%u)",
+ (uint8_t)slave_idx, slave->port_id,
+ test_params.bonded_port_id);
+
+ slave->bonded = 0;
+ slave->lacp_parnter_state = 0;
+ return 0;
+}
+
+static int
+initialize_bonded_device_with_slaves(uint8_t slave_count, uint8_t start)
+{
+ uint8_t i;
+
+ RTE_VERIFY(test_params.bonded_port_id != INVALID_PORT_ID);
+
+ for (i = 0; i < slave_count; i++) {
+ TEST_ASSERT_SUCCESS(add_slave(&test_params.slave_ports[i], 1),
+ "Failed to add port %u to bonded device.\n",
+ test_params.slave_ports[i].port_id);
+ }
+
+ /* Reset mode 4 configuration */
+ rte_eth_bond_8023ad_setup(test_params.bonded_port_id, NULL);
+ rte_eth_promiscuous_disable(test_params.bonded_port_id);
+
+ if (start)
+ TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bonded_port_id),
+ "Failed to start bonded device");
+
+ return TEST_SUCCESS;
+}
+
+static int
+remove_slaves_and_stop_bonded_device(void)
+{
+ struct slave_conf *slave;
+ int retval;
+ uint8_t slaves[RTE_MAX_ETHPORTS];
+ uint8_t i;
+
+ rte_eth_dev_stop(test_params.bonded_port_id);
+
+ FOR_EACH_SLAVE(i, slave)
+ remove_slave(slave);
+
+ retval = rte_eth_bond_slaves_get(test_params.bonded_port_id, slaves,
+ RTE_DIM(slaves));
+
+ TEST_ASSERT_EQUAL(retval, 0,
+ "Expected bonded device %u have 0 slaves but returned %d.",
+ test_params.bonded_port_id, retval);
+
+ FOR_EACH_PORT(i, slave) {
+ rte_eth_dev_stop(slave->port_id);
+
+ TEST_ASSERT(slave->bonded == 0,
+ "Port id=%u is still marked as enslaved.", slave->port_id);
+ }
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_setup(void)
+{
+ int retval, nb_mbuf_per_pool;
+ char name[RTE_ETH_NAME_MAX_LEN];
+ struct slave_conf *port;
+ const uint8_t socket_id = rte_socket_id();
+ uint8_t i;
+
+ if (test_params.mbuf_pool == NULL) {
+ nb_mbuf_per_pool = TEST_RX_DESC_MAX + DEF_PKT_BURST +
+ TEST_TX_DESC_MAX + MAX_PKT_BURST;
+ test_params.mbuf_pool = rte_mempool_create("TEST_MODE4",
+ nb_mbuf_per_pool, MBUF_SIZE, MBUF_CACHE_SIZE,
+ sizeof(struct rte_pktmbuf_pool_private),
+ rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
+ socket_id, 0);
+
+ TEST_ASSERT(test_params.mbuf_pool != NULL,
+ "rte_mempool_create failed\n");
+ }
+
+ /* Create / initialize ring eth devs. */
+ FOR_EACH_PORT(i, port) {
+ port = &test_params.slave_ports[i];
+
+ if (port->rx_queue == NULL) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_RX_QUEUE_FMT, i);
+ TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long");
+ port->rx_queue = rte_ring_create(name, RX_RING_SIZE, socket_id, 0);
+ TEST_ASSERT(port->rx_queue != NULL,
+ "Failed to allocate rx ring '%s': %s", name,
+ rte_strerror(rte_errno));
+ }
+
+ if (port->tx_queue == NULL) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_TX_QUEUE_FMT, i);
+ TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long");
+ port->tx_queue = rte_ring_create(name, TX_RING_SIZE, socket_id, 0);
+ TEST_ASSERT_NOT_NULL(port->tx_queue,
+ "Failed to allocate tx ring '%s': %s", name,
+ rte_strerror(rte_errno));
+ }
+
+ if (port->port_id == INVALID_PORT_ID) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_DEV_NAME_FMT, i);
+ TEST_ASSERT(retval < (int)RTE_DIM(name) - 1, "Name too long");
+ retval = rte_eth_from_rings(name, &port->rx_queue, 1,
+ &port->tx_queue, 1, socket_id);
+ TEST_ASSERT(retval >= 0,
+ "Failed to create ring ethdev '%s'\n", name);
+
+ port->port_id = rte_eth_dev_count() - 1;
+ }
+
+ retval = configure_ethdev(port->port_id, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to configure virtual ethdev %s\n",
+ name);
+ }
+
+ if (test_params.bonded_port_id == INVALID_PORT_ID) {
+ retval = rte_eth_bond_create(BONDED_DEV_NAME, BONDING_MODE_8023AD,
+ socket_id);
+
+ TEST_ASSERT(retval >= 0, "Failed to create bonded ethdev %s",
+ BONDED_DEV_NAME);
+
+ test_params.bonded_port_id = retval;
+ TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bonded_port_id, 0),
+ "Failed to configure bonded ethdev %s", BONDED_DEV_NAME);
+ } else if (rte_eth_bond_mode_get(test_params.bonded_port_id) !=
+ BONDING_MODE_8023AD) {
+ TEST_ASSERT(rte_eth_bond_mode_set(test_params.bonded_port_id,
+ BONDING_MODE_8023AD) == 0,
+ "Failed to set ethdev %d to mode %d",
+ test_params.bonded_port_id, BONDING_MODE_8023AD);
+ }
+
+ return 0;
+}
+
+static int
+testsuite_teardown(void)
+{
+ struct slave_conf *port;
+ uint8_t i;
+
+ /* Only stop ports.
+ * Any cleanup/reset state is done when particular test is
+ * started. */
+
+ rte_eth_dev_stop(test_params.bonded_port_id);
+
+ FOR_EACH_PORT(i, port)
+ rte_eth_dev_stop(port->port_id);
+
+ return 0;
+}
+
+/*
+ * Check if given LACP packet. If it is, make make replay packet to force
+ * COLLECTING state.
+ * return 0 when pkt is LACP frame, 1 if it is not slow frame, 2 if it is slow
+ * frame but not LACP
+ */
+static int
+make_lacp_reply(struct slave_conf *slave, struct rte_mbuf *pkt)
+{
+ struct ether_hdr *hdr;
+ struct slow_protocol_frame *slow_hdr;
+ struct lacpdu *lacp;
+
+ /* look for LACP */
+ hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ if (hdr->ether_type != rte_cpu_to_be_16(ETHER_TYPE_SLOW))
+ return 1;
+
+ slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *);
+ /* ignore packets of other types */
+ if (slow_hdr->slow_protocol.subtype != SLOW_SUBTYPE_LACP)
+ return 2;
+
+ slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *);
+
+ /* Change source address to partner address */
+ ether_addr_copy(&parnter_mac_default, &slow_hdr->eth_hdr.s_addr);
+ slow_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+
+ lacp = (struct lacpdu *) &slow_hdr->slow_protocol;
+ /* Save last received state */
+ slave->lacp_parnter_state = lacp->actor.state;
+ /* Change it into LACP replay by matching parameters. */
+ memcpy(&lacp->partner.port_params, &lacp->actor.port_params,
+ sizeof(struct port_params));
+
+ lacp->partner.state = lacp->actor.state;
+
+ ether_addr_copy(&parnter_system, &lacp->actor.port_params.system);
+ lacp->actor.state = STATE_LACP_ACTIVE |
+ STATE_SYNCHRONIZATION |
+ STATE_AGGREGATION |
+ STATE_COLLECTING |
+ STATE_DISTRIBUTING;
+
+ return 0;
+}
+
+/*
+ * Reads packets from given slave, search for LACP packet and reply them.
+ *
+ * Receives burst of packets from slave. Looks for LACP packet. Drops
+ * all other packets. Prepares response LACP and sends it back.
+ *
+ * return number of LACP received and replied, -1 on error.
+ */
+static int
+bond_handshake_reply(struct slave_conf *slave)
+{
+ int retval;
+ struct rte_mbuf *rx_buf[MAX_PKT_BURST];
+ struct rte_mbuf *lacp_tx_buf[MAX_PKT_BURST];
+ uint16_t lacp_tx_buf_cnt = 0, i;
+
+ retval = slave_get_pkts(slave, rx_buf, RTE_DIM(rx_buf));
+ TEST_ASSERT(retval >= 0, "Getting slave %u packets failed.",
+ slave->port_id);
+
+ for (i = 0; i < (uint16_t)retval; i++) {
+ if (make_lacp_reply(slave, rx_buf[i]) == 0) {
+ /* reply with actor's LACP */
+ lacp_tx_buf[lacp_tx_buf_cnt++] = rx_buf[i];
+ } else
+ rte_pktmbuf_free(rx_buf[i]);
+ }
+
+ if (lacp_tx_buf_cnt == 0)
+ return 0;
+
+ retval = slave_put_pkts(slave, lacp_tx_buf, lacp_tx_buf_cnt);
+ if (retval <= lacp_tx_buf_cnt) {
+ /* retval might be negative */
+ for (i = RTE_MAX(0, retval); retval < lacp_tx_buf_cnt; retval++)
+ rte_pktmbuf_free(lacp_tx_buf[i]);
+ }
+
+ TEST_ASSERT_EQUAL(retval, lacp_tx_buf_cnt,
+ "Failed to equeue lacp packets into slave %u tx queue.",
+ slave->port_id);
+
+ return lacp_tx_buf_cnt;
+}
+
+/*
+ * Function check if given slave tx queue contains packets that make mode 4
+ * handshake complete. It will drain slave queue.
+ * return 0 if handshake not completed, 1 if handshake was complete,
+ */
+static int
+bond_handshake_done(struct slave_conf *slave)
+{
+ const uint8_t expected_state = STATE_LACP_ACTIVE | STATE_SYNCHRONIZATION |
+ STATE_AGGREGATION | STATE_COLLECTING | STATE_DISTRIBUTING;
+
+ return slave->lacp_parnter_state == expected_state;
+}
+
+static unsigned
+bond_get_update_timeout_ms(void)
+{
+ struct rte_eth_bond_8023ad_conf conf;
+
+ rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf);
+ return conf.update_timeout_ms;
+}
+
+/*
+ * Exchanges LACP packets with partner to achieve dynamic port configuration.
+ * return TEST_SUCCESS if initial handshake succeed, TEST_FAILED otherwise.
+ */
+static int
+bond_handshake(void)
+{
+ struct slave_conf *slave;
+ struct rte_mbuf *buf[MAX_PKT_BURST];
+ uint16_t nb_pkts;
+ uint8_t all_slaves_done, i, j;
+ uint8_t status[RTE_DIM(test_params.slave_ports)] = { 0 };
+ const unsigned delay = bond_get_update_timeout_ms();
+
+ /* Exchange LACP frames */
+ all_slaves_done = 0;
+ for (i = 0; i < 30 && all_slaves_done == 0; ++i) {
+ rte_delay_ms(delay);
+
+ all_slaves_done = 1;
+ FOR_EACH_SLAVE(j, slave) {
+ /* If response already send, skip slave */
+ if (status[j] != 0)
+ continue;
+
+ if (bond_handshake_reply(slave) < 0) {
+ all_slaves_done = 0;
+ break;
+ }
+
+ status[j] = bond_handshake_done(slave);
+ if (status[j] == 0)
+ all_slaves_done = 0;
+ }
+
+ nb_pkts = bond_tx(NULL, 0);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets transmitted unexpectedly");
+
+ nb_pkts = bond_rx(buf, RTE_DIM(buf));
+ free_pkts(buf, nb_pkts);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets received unexpectedly");
+ }
+ /* If response didn't send - report failure */
+ TEST_ASSERT_EQUAL(all_slaves_done, 1, "Bond handshake failed\n");
+
+ /* If flags doesn't match - report failure */
+ return all_slaves_done = 1 ? TEST_SUCCESS : TEST_FAILED;
+}
+
+#define TEST_LACP_SLAVE_COUT RTE_DIM(test_params.slave_ports)
+static int
+test_mode4_lacp(void)
+{
+ int retval;
+
+ retval = initialize_bonded_device_with_slaves(TEST_LACP_SLAVE_COUT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ /* Test LACP handshake function */
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+generate_packets(struct ether_addr *src_mac,
+ struct ether_addr *dst_mac, uint16_t count, struct rte_mbuf **buf)
+{
+ uint16_t pktlen = PACKET_BURST_GEN_PKT_LEN;
+ uint8_t vlan_enable = 0;
+ uint16_t vlan_id = 0;
+ uint8_t ip4_type = 1; /* 0 - ipv6 */
+
+ uint16_t src_port = 10, dst_port = 20;
+
+ uint32_t ip_src[4] = { [0 ... 2] = 0xDEADBEEF, [3] = IPv4(192, 168, 0, 1) };
+ uint32_t ip_dst[4] = { [0 ... 2] = 0xFEEDFACE, [3] = IPv4(192, 168, 0, 2) };
+
+ struct ether_hdr pkt_eth_hdr;
+ struct udp_hdr pkt_udp_hdr;
+ union {
+ struct ipv4_hdr v4;
+ struct ipv6_hdr v6;
+ } pkt_ip_hdr;
+
+ int retval;
+
+ initialize_eth_header(&pkt_eth_hdr, src_mac, dst_mac, vlan_enable, vlan_id);
+
+ if (ip4_type)
+ initialize_ipv4_header(&pkt_ip_hdr.v4, ip_src[3], ip_dst[3], pktlen);
+ else
+ initialize_ipv6_header(&pkt_ip_hdr.v6, (uint8_t *)ip_src,
+ (uint8_t *)&ip_dst, pktlen);
+
+ initialize_udp_header(&pkt_udp_hdr, src_port, dst_port, 16);
+
+ retval = generate_packet_burst(test_params.mbuf_pool, buf,
+ &pkt_eth_hdr, vlan_enable, &pkt_ip_hdr, 1, &pkt_udp_hdr,
+ count, pktlen, 1);
+
+ if (retval > 0 && retval != count)
+ free_pkts(&buf[count - retval], retval);
+
+ TEST_ASSERT_EQUAL(retval, count, "Failed to generate %u packets",
+ count);
+
+ return count;
+}
+
+static int
+generate_and_put_packets(struct slave_conf *slave, struct ether_addr *src_mac,
+ struct ether_addr *dst_mac, uint16_t count)
+{
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+
+ retval = generate_packets(src_mac, dst_mac, count, pkts);
+ if (retval != (int)count)
+ return retval;
+
+ retval = slave_put_pkts(slave, pkts, count);
+ if (retval > 0 && retval != count)
+ free_pkts(&pkts[retval], count - retval);
+
+ TEST_ASSERT_EQUAL(retval, count,
+ "Failed to enqueue packets into slave %u RX queue", slave->port_id);
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_rx(void)
+{
+ struct slave_conf *slave;
+ uint16_t i, j;
+
+ uint16_t expected_pkts_cnt;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+ unsigned delay;
+
+ struct ether_hdr *hdr;
+
+ struct ether_addr src_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } };
+ struct ether_addr dst_mac;
+ struct ether_addr bonded_mac;
+
+ retval = initialize_bonded_device_with_slaves(TEST_PROMISC_SLAVE_COUNT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac);
+ ether_addr_copy(&bonded_mac, &dst_mac);
+
+ /* Assert that dst address is not bonding address */
+ dst_mac.addr_bytes[0]++;
+
+ /* First try with promiscuous mode enabled.
+ * Add 2 packets to each slave. First with bonding MAC address, second with
+ * different. Check if we received all of them. */
+ rte_eth_promiscuous_enable(test_params.bonded_port_id);
+
+ expected_pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ /* Expect 2 packets per slave */
+ expected_pkts_cnt += 2;
+ }
+
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval == expected_pkts_cnt) {
+ int cnt[2] = { 0, 0 };
+
+ for (i = 0; i < expected_pkts_cnt; i++) {
+ hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+ cnt[is_same_ether_addr(&hdr->d_addr, &bonded_mac)]++;
+ }
+
+ free_pkts(pkts, expected_pkts_cnt);
+
+ /* For division by 2 expected_pkts_cnt must be even */
+ RTE_VERIFY((expected_pkts_cnt & 1) == 0);
+ TEST_ASSERT(cnt[0] == expected_pkts_cnt / 2 &&
+ cnt[1] == expected_pkts_cnt / 2,
+ "Expected %u packets with the same MAC and %u with different but "
+ "got %u with the same and %u with diffrent MAC",
+ expected_pkts_cnt / 2, expected_pkts_cnt / 2, cnt[1], cnt[0]);
+ } else if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, expected_pkts_cnt,
+ "Expected %u packets but received only %d", expected_pkts_cnt, retval);
+
+ /* Now, disable promiscuous mode. When promiscuous mode is disabled we
+ * expect to receive only packets that are directed to bonding port. */
+ rte_eth_promiscuous_disable(test_params.bonded_port_id);
+
+ expected_pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ /* Expect only one packet per slave */
+ expected_pkts_cnt += 1;
+ }
+
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval == expected_pkts_cnt) {
+ int eq_cnt = 0;
+
+ for (i = 0; i < expected_pkts_cnt; i++) {
+ hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+ eq_cnt += is_same_ether_addr(&hdr->d_addr, &bonded_mac);
+ }
+
+ free_pkts(pkts, expected_pkts_cnt);
+ TEST_ASSERT_EQUAL(eq_cnt, expected_pkts_cnt, "Packet address mismatch");
+ } else if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, expected_pkts_cnt,
+ "Expected %u packets but received only %d", expected_pkts_cnt, retval);
+
+ /* Link down test: simulate link down for first slave. */
+ delay = bond_get_update_timeout_ms();
+
+ uint8_t slave_down_id = INVALID_PORT_ID;
+
+ /* Find first slave and make link down on it*/
+ FOR_EACH_SLAVE(i, slave) {
+ rte_eth_dev_set_link_down(slave->port_id);
+ slave_down_id = slave->port_id;
+ break;
+ }
+
+ RTE_VERIFY(slave_down_id != INVALID_PORT_ID);
+
+ /* Give some time to rearrange bonding */
+ for (i = 0; i < 3; i++) {
+ rte_delay_ms(delay);
+ bond_handshake();
+ }
+
+ TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed");
+
+ /* Put packet to each slave */
+ FOR_EACH_SLAVE(i, slave) {
+ void *pkt = NULL;
+
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst.");
+
+ src_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst.");
+
+ retval = bond_rx(pkts, RTE_DIM(pkts));
+
+ /* Clean anything */
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ while (rte_ring_dequeue(slave->rx_queue, (void **)&pkt) == 0)
+ rte_pktmbuf_free(pkt);
+
+ if (slave_down_id == slave->port_id)
+ TEST_ASSERT_EQUAL(retval, 0, "Packets received unexpectedly.");
+ else
+ TEST_ASSERT_NOT_EQUAL(retval, 0,
+ "Expected to receive some packets on slave %u.",
+ slave->port_id);
+ rte_eth_dev_start(slave->port_id);
+
+ for (j = 0; j < 5; j++) {
+ TEST_ASSERT(bond_handshake_reply(slave) >= 0,
+ "Handshake after link up");
+
+ if (bond_handshake_done(slave) == 1)
+ break;
+ }
+
+ TEST_ASSERT(j < 5, "Failed to agregate slave after link up");
+ }
+
+ remove_slaves_and_stop_bonded_device();
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_tx_burst(void)
+{
+ struct slave_conf *slave;
+ uint16_t i, j;
+
+ uint16_t exp_pkts_cnt, pkts_cnt = 0;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+ unsigned delay;
+
+ struct ether_addr dst_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } };
+ struct ether_addr bonded_mac;
+
+ retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac);
+
+ /* Prepare burst */
+ for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) {
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt;
+ retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]);
+
+ if (retval != 1)
+ free_pkts(pkts, pkts_cnt);
+
+ TEST_ASSERT_EQUAL(retval, 1, "Failed to generate packet %u", pkts_cnt);
+ }
+ exp_pkts_cnt = pkts_cnt;
+
+ /* Transmit packets on bonded device */
+ retval = bond_tx(pkts, pkts_cnt);
+ if (retval > 0 && retval < pkts_cnt)
+ free_pkts(&pkts[retval], pkts_cnt - retval);
+
+ TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed");
+
+ /* Check if packets were transmitted properly. Every slave should have
+ * at least one packet, and sum must match. Under normal operation
+ * there should be no LACP nor MARKER frames. */
+ pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ uint16_t normal_cnt, slow_cnt;
+
+ retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts));
+ normal_cnt = 0;
+ slow_cnt = 0;
+
+ for (j = 0; j < retval; j++) {
+ if (make_lacp_reply(slave, pkts[j]) == 1)
+ normal_cnt++;
+ else
+ slow_cnt++;
+ }
+
+ free_pkts(pkts, normal_cnt + slow_cnt);
+ TEST_ASSERT_EQUAL(slow_cnt, 0,
+ "slave %u unexpectedly transmitted %d SLOW packets", slave->port_id,
+ slow_cnt);
+
+ TEST_ASSERT_NOT_EQUAL(normal_cnt, 0,
+ "slave %u did not transmitted any packets", slave->port_id);
+
+ pkts_cnt += normal_cnt;
+ }
+
+ TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt,
+ "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt);
+
+ /* Link down test:
+ * simulate link down for first slave. */
+ delay = bond_get_update_timeout_ms();
+
+ uint8_t slave_down_id = INVALID_PORT_ID;
+
+ FOR_EACH_SLAVE(i, slave) {
+ rte_eth_dev_set_link_down(slave->port_id);
+ slave_down_id = slave->port_id;
+ break;
+ }
+
+ RTE_VERIFY(slave_down_id != INVALID_PORT_ID);
+
+ /* Give some time to rearrange bonding. */
+ for (i = 0; i < 3; i++) {
+ bond_handshake();
+ rte_delay_ms(delay);
+ }
+
+ TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed");
+
+ /* Prepare burst. */
+ for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) {
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt;
+ retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]);
+
+ if (retval != 1)
+ free_pkts(pkts, pkts_cnt);
+
+ TEST_ASSERT_EQUAL(retval, 1, "Failed to generate test packet %u",
+ pkts_cnt);
+ }
+ exp_pkts_cnt = pkts_cnt;
+
+ /* Transmit packets on bonded device. */
+ retval = bond_tx(pkts, pkts_cnt);
+ if (retval > 0 && retval < pkts_cnt)
+ free_pkts(&pkts[retval], pkts_cnt - retval);
+
+ TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed");
+
+ /* Check if packets was transmitted properly. Every slave should have
+ * at least one packet, and sum must match. Under normal operation
+ * there should be no LACP nor MARKER frames. */
+ pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ uint16_t normal_cnt, slow_cnt;
+
+ retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts));
+ normal_cnt = 0;
+ slow_cnt = 0;
+
+ for (j = 0; j < retval; j++) {
+ if (make_lacp_reply(slave, pkts[j]) == 1)
+ normal_cnt++;
+ else
+ slow_cnt++;
+ }
+
+ free_pkts(pkts, normal_cnt + slow_cnt);
+
+ if (slave_down_id == slave->port_id) {
+ TEST_ASSERT_EQUAL(normal_cnt + slow_cnt, 0,
+ "slave %u enexpectedly transmitted %u packets",
+ normal_cnt + slow_cnt, slave->port_id);
+ } else {
+ TEST_ASSERT_EQUAL(slow_cnt, 0,
+ "slave %u unexpectedly transmitted %d SLOW packets",
+ slave->port_id, slow_cnt);
+
+ TEST_ASSERT_NOT_EQUAL(normal_cnt, 0,
+ "slave %u did not transmitted any packets", slave->port_id);
+ }
+
+ pkts_cnt += normal_cnt;
+ }
+
+ TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt,
+ "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt);
+
+ return remove_slaves_and_stop_bonded_device();
+}
+
+static void
+init_marker(struct rte_mbuf *pkt, struct slave_conf *slave)
+{
+ struct marker_header *marker_hdr = rte_pktmbuf_mtod(pkt,
+ struct marker_header *);
+
+ /* Copy multicast destination address */
+ ether_addr_copy(&slow_protocol_mac_addr, &marker_hdr->eth_hdr.d_addr);
+
+ /* Init source address */
+ ether_addr_copy(&parnter_mac_default, &marker_hdr->eth_hdr.s_addr);
+ marker_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN-1] = slave->port_id;
+
+ marker_hdr->eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_SLOW);
+
+ marker_hdr->marker.subtype = SLOW_SUBTYPE_MARKER;
+ marker_hdr->marker.version_number = 1;
+ marker_hdr->marker.tlv_type_marker = MARKER_TLV_TYPE_INFO;
+ marker_hdr->marker.info_length =
+ offsetof(struct marker, reserved_90) -
+ offsetof(struct marker, requester_port);
+ RTE_VERIFY(marker_hdr->marker.info_length == 16);
+ marker_hdr->marker.requester_port = slave->port_id + 1;
+ marker_hdr->marker.tlv_type_terminator = TLV_TYPE_TERMINATOR_INFORMATION;
+ marker_hdr->marker.terminator_length = 0;
+}
+
+static int
+test_mode4_marker(void)
+{
+ struct slave_conf *slave;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ struct rte_mbuf *marker_pkt;
+ struct marker_header *marker_hdr;
+
+ unsigned delay;
+ int retval;
+ uint16_t nb_pkts;
+ uint8_t i, j;
+ const uint16_t ethtype_slow_be = rte_be_to_cpu_16(ETHER_TYPE_SLOW);
+
+ retval = initialize_bonded_device_with_slaves(TEST_MARKER_SLAVE_COUT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ /* Test LACP handshake function */
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ delay = bond_get_update_timeout_ms();
+ FOR_EACH_SLAVE(i, slave) {
+ marker_pkt = rte_pktmbuf_alloc(test_params.mbuf_pool);
+ TEST_ASSERT_NOT_NULL(marker_pkt, "Failed to allocate marker packet");
+ init_marker(marker_pkt, slave);
+
+ retval = slave_put_pkts(slave, &marker_pkt, 1);
+ if (retval != 1)
+ rte_pktmbuf_free(marker_pkt);
+
+ TEST_ASSERT_EQUAL(retval, 1,
+ "Failed to send marker packet to slave %u", slave->port_id);
+
+ for (j = 0; j < 20; ++j) {
+ rte_delay_ms(delay);
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 0, "Received packets unexpectedly");
+
+ retval = rte_eth_tx_burst(test_params.bonded_port_id, 0, NULL, 0);
+ TEST_ASSERT_EQUAL(retval, 0,
+ "Requested TX of 0 packets but %d transmitted", retval);
+
+ /* Check if LACP packet was send by state machines
+ First and only packet must be a maker response */
+ retval = slave_get_pkts(slave, pkts, MAX_PKT_BURST);
+ if (retval == 0)
+ continue;
+ if (retval > 1)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 1, "failed to get slave packets");
+ nb_pkts = retval;
+
+ marker_hdr = rte_pktmbuf_mtod(pkts[0], struct marker_header *);
+ /* Check if it's slow packet*/
+ if (marker_hdr->eth_hdr.ether_type != ethtype_slow_be)
+ retval = -1;
+ /* Check if it's marker packet */
+ else if (marker_hdr->marker.subtype != SLOW_SUBTYPE_MARKER)
+ retval = -2;
+ else if (marker_hdr->marker.tlv_type_marker != MARKER_TLV_TYPE_RESP)
+ retval = -3;
+
+ free_pkts(pkts, nb_pkts);
+
+ TEST_ASSERT_NOT_EQUAL(retval, -1, "Unexpected protocol type");
+ TEST_ASSERT_NOT_EQUAL(retval, -2, "Unexpected sub protocol type");
+ TEST_ASSERT_NOT_EQUAL(retval, -3, "Unexpected marker type");
+ break;
+ }
+
+ TEST_ASSERT(j < 20, "Marker response not found");
+ }
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_expired(void)
+{
+ struct slave_conf *slave, *exp_slave = NULL;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ struct rte_mbuf *pkt = NULL;
+ int retval;
+ uint32_t old_delay;
+
+ uint8_t i;
+ uint16_t j;
+
+ struct rte_eth_bond_8023ad_conf conf;
+
+ retval = initialize_bonded_device_with_slaves(TEST_EXPIRED_SLAVE_COUNT, 1);
+ /* Set custom timeouts to make test last shorter. */
+ rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf);
+ conf.fast_periodic_ms = 100;
+ conf.slow_periodic_ms = 600;
+ conf.short_timeout_ms = 300;
+ conf.long_timeout_ms = 900;
+ conf.aggregate_wait_timeout_ms = 200;
+ conf.tx_period_ms = 100;
+ old_delay = conf.update_timeout_ms;
+ conf.update_timeout_ms = 10;
+ rte_eth_bond_8023ad_setup(test_params.bonded_port_id, &conf);
+
+ /* Wait for new settings to be applied. */
+ for (i = 0; i < old_delay/conf.update_timeout_ms * 2; i++) {
+ FOR_EACH_SLAVE(j, slave)
+ bond_handshake_reply(slave);
+
+ rte_delay_ms(conf.update_timeout_ms);
+ }
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ /* Find first slave */
+ FOR_EACH_SLAVE(i, slave) {
+ exp_slave = slave;
+ break;
+ }
+
+ RTE_VERIFY(exp_slave != NULL);
+
+ /* When one of partners do not send or respond to LACP frame in
+ * conf.long_timeout_ms time, internal state machines should detect this
+ * and transit to expired state. */
+ for (j = 0; j < conf.long_timeout_ms/conf.update_timeout_ms + 2; j++) {
+ rte_delay_ms(conf.update_timeout_ms);
+
+ retval = bond_tx(NULL, 0);
+ TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets",
+ retval);
+
+ FOR_EACH_SLAVE(i, slave) {
+ retval = bond_handshake_reply(slave);
+ TEST_ASSERT(retval >= 0, "Handshake failed");
+
+ /* Remove replay for slave that supose to be expired. */
+ if (slave == exp_slave) {
+ while (rte_ring_count(slave->rx_queue) > 0) {
+ rte_ring_dequeue(slave->rx_queue, (void **)&pkt);
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+
+ retval = bond_rx(pkts, RTE_DIM(pkts));
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets",
+ retval);
+ }
+
+ /* After test only expected slave should be in EXPIRED state */
+ FOR_EACH_SLAVE(i, slave) {
+ if (slave == exp_slave)
+ TEST_ASSERT(slave->lacp_parnter_state & STATE_EXPIRED,
+ "Slave %u should be in expired.", slave->port_id);
+ else
+ TEST_ASSERT_EQUAL(bond_handshake_done(slave), 1,
+ "Slave %u should be operational.", slave->port_id);
+ }
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+check_environment(void)
+{
+ struct slave_conf *port;
+ uint8_t i, env_state;
+ uint8_t slaves[RTE_DIM(test_params.slave_ports)];
+ int slaves_count;
+
+ env_state = 0;
+ FOR_EACH_PORT(i, port) {
+ if (rte_ring_count(port->rx_queue) != 0)
+ env_state |= 0x01;
+
+ if (rte_ring_count(port->tx_queue) != 0)
+ env_state |= 0x02;
+
+ if (port->bonded != 0)
+ env_state |= 0x04;
+
+ if (port->lacp_parnter_state != 0)
+ env_state |= 0x08;
+
+ if (env_state != 0)
+ break;
+ }
+
+ slaves_count = rte_eth_bond_slaves_get(test_params.bonded_port_id,
+ slaves, RTE_DIM(slaves));
+
+ if (slaves_count != 0)
+ env_state |= 0x10;
+
+ TEST_ASSERT_EQUAL(env_state, 0,
+ "Environment not clean (port %u):%s%s%s%s%s",
+ port->port_id,
+ env_state & 0x01 ? " slave rx queue not clean" : "",
+ env_state & 0x02 ? " slave tx queue not clean" : "",
+ env_state & 0x04 ? " port marked as enslaved" : "",
+ env_state & 0x80 ? " slave state is not reset" : "",
+ env_state & 0x10 ? " slave count not equal 0" : ".");
+
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_executor(int (*test_func)(void))
+{
+ struct slave_conf *port;
+ int test_result;
+ uint8_t i;
+ void *pkt;
+
+ /* Check if environment is clean. Fail to launch a test if there was
+ * a critical error before that prevented to reset environment. */
+ TEST_ASSERT_SUCCESS(check_environment(),
+ "Refusing to launch test in dirty environment.");
+
+ RTE_VERIFY(test_func != NULL);
+ test_result = (*test_func)();
+
+ /* If test succeed check if environment wast left in good condition. */
+ if (test_result == TEST_SUCCESS)
+ test_result = check_environment();
+
+ /* Reset environment in case test failed to do that. */
+ if (test_result != TEST_SUCCESS) {
+ TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(),
+ "Failed to stop bonded device");
+
+ FOR_EACH_PORT(i, port) {
+ while (rte_ring_count(port->rx_queue) != 0) {
+ if (rte_ring_dequeue(port->rx_queue, &pkt) == 0)
+ rte_pktmbuf_free(pkt);
+ }
+
+ while (rte_ring_count(port->tx_queue) != 0) {
+ if (rte_ring_dequeue(port->tx_queue, &pkt) == 0)
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+
+ return test_result;
+}
+
+static int
+test_mode4_lacp_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_lacp);
+}
+
+static int
+test_mode4_marker_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_marker);
+}
+
+static int
+test_mode4_rx_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_rx);
+}
+
+static int
+test_mode4_tx_burst_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_tx_burst);
+}
+
+static int
+test_mode4_expired_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_expired);
+}
+
+static struct unit_test_suite link_bonding_mode4_test_suite = {
+ .suite_name = "Link Bonding mode 4 Unit Test Suite",
+ .setup = test_setup,
+ .teardown = testsuite_teardown,
+ .unit_test_cases = {
+ TEST_CASE_NAMED("test_mode4_lacp", test_mode4_lacp_wrapper),
+ TEST_CASE_NAMED("test_mode4_rx", test_mode4_rx_wrapper),
+ TEST_CASE_NAMED("test_mode4_tx_burst", test_mode4_tx_burst_wrapper),
+ TEST_CASE_NAMED("test_mode4_marker", test_mode4_marker_wrapper),
+ TEST_CASE_NAMED("test_mode4_expired", test_mode4_expired_wrapper),
+ { NULL, NULL, NULL, NULL, NULL } /**< NULL terminate unit test array */
+ }
+};
+
+static int
+test_link_bonding_mode4(void)
+{
+ return unit_test_suite_runner(&link_bonding_mode4_test_suite);
+}
+
+static struct test_command link_bonding_cmd = {
+ .command = "link_bonding_mode4_autotest",
+ .callback = test_link_bonding_mode4,
+};
+
+REGISTER_TEST_COMMAND(link_bonding_cmd);
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v3] mk: Link test app against librte_pmd_ring when needed
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 0/3] " Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 1/3] test: test.h rework Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 2/3] test: Unit tests for mode 4 Tomasz Kulasek
@ 2015-01-29 8:51 ` Tomasz Kulasek
2015-02-12 11:50 ` Declan Doherty
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Tomasz Kulasek
3 siblings, 1 reply; 30+ messages in thread
From: Tomasz Kulasek @ 2015-01-29 8:51 UTC (permalink / raw)
To: dev
This patch links test application against librte_pmd_ring.so for shared
libraries. It's required as long as librte_pmd_ring provides some aditional
routines used for configuration and testing purposes and must be
"hard-linked".
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
app/test/Makefile | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/app/test/Makefile b/app/test/Makefile
index ee0e95a..04e6396 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -128,8 +128,12 @@ SRCS-y += test_devargs.c
SRCS-y += virtual_pmd.c
SRCS-y += packet_burst_generator.c
SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_RING),y)
SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding_mode4.c
+endif
+
SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring.c
SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c
@@ -147,6 +151,17 @@ CFLAGS += -D_GNU_SOURCE
# this application needs libraries first
DEPDIRS-y += lib
+# Link against shared libraries when needed
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
+ifneq ($(CONFIG_RTE_LIBRTE_PMD_RING),y)
+$(error Link bonding tests require CONFIG_RTE_LIBRTE_PMD_RING=y)
+else
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+LDLIBS += -lrte_pmd_ring
+endif
+endif
+endif
+
include $(RTE_SDK)/mk/rte.app.mk
endif
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH v3 2/3] test: Unit tests for mode 4
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 2/3] test: Unit tests for mode 4 Tomasz Kulasek
@ 2015-02-12 11:49 ` Declan Doherty
0 siblings, 0 replies; 30+ messages in thread
From: Declan Doherty @ 2015-02-12 11:49 UTC (permalink / raw)
To: Tomasz Kulasek, dev
On 29/01/15 08:51, Tomasz Kulasek wrote:
> This patch adds unit tests for mode 4. It is split into separate
> file to avoid problems with other modes that does not need to
> look into packets payload.
> This patch includes also a modification of maximum number of ports
> used in their tests for bonding modes 0-3 from 16 to 6.
>
> v3 changes
> - Patch re-created for current release to maintain consistency
>
>
> Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
> Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
> ---
> app/test/Makefile | 1 +
> app/test/test_link_bonding.c | 2 +-
> app/test/test_link_bonding_mode4.c | 1412 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 1414 insertions(+), 1 deletion(-)
> create mode 100644 app/test/test_link_bonding_mode4.c
>
>....
>
Hey Tomasz,
due to commit # ecd9d5193b85f22ff3d5fa76fb26d1363b293d94 which modified
the initialize_eth_header API you need to make the following
modification for a clean compilation.
diff --git a/app/test/test_link_bonding_mode4.c
b/app/test/test_link_bonding_mode4.c
index f8d0955..c35129f 100644
--- a/app/test/test_link_bonding_mode4.c
+++ b/app/test/test_link_bonding_mode4.c
@@ -684,7 +684,8 @@ generate_packets(struct ether_addr *src_mac,
int retval;
- initialize_eth_header(&pkt_eth_hdr, src_mac, dst_mac,
vlan_enable, vlan_id);
+ initialize_eth_header(&pkt_eth_hdr, src_mac, dst_mac, ip4_type,
+ vlan_enable, vlan_id);
if (ip4_type)
initialize_ipv4_header(&pkt_ip_hdr.v4, ip_src[3],
ip_dst[3], pktlen);
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH v3] mk: Link test app against librte_pmd_ring when needed
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3] mk: Link test app against librte_pmd_ring when needed Tomasz Kulasek
@ 2015-02-12 11:50 ` Declan Doherty
0 siblings, 0 replies; 30+ messages in thread
From: Declan Doherty @ 2015-02-12 11:50 UTC (permalink / raw)
To: Tomasz Kulasek, dev
On 29/01/15 08:51, Tomasz Kulasek wrote:
> This patch links test application against librte_pmd_ring.so for shared
> libraries. It's required as long as librte_pmd_ring provides some aditional
> routines used for configuration and testing purposes and must be
> "hard-linked".
>
> Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
> ---
> app/test/Makefile | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/app/test/Makefile b/app/test/Makefile
> index ee0e95a..04e6396 100644
> --- a/app/test/Makefile
> +++ b/app/test/Makefile
> @@ -128,8 +128,12 @@ SRCS-y += test_devargs.c
> SRCS-y += virtual_pmd.c
> SRCS-y += packet_burst_generator.c
> SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
> +
> +ifeq ($(CONFIG_RTE_LIBRTE_PMD_RING),y)
> SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding.c
> SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding_mode4.c
> +endif
> +
> SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring.c
> SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c
>
> @@ -147,6 +151,17 @@ CFLAGS += -D_GNU_SOURCE
> # this application needs libraries first
> DEPDIRS-y += lib
>
> +# Link against shared libraries when needed
> +ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
> +ifneq ($(CONFIG_RTE_LIBRTE_PMD_RING),y)
> +$(error Link bonding tests require CONFIG_RTE_LIBRTE_PMD_RING=y)
> +else
> +ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
> +LDLIBS += -lrte_pmd_ring
> +endif
> +endif
> +endif
> +
> include $(RTE_SDK)/mk/rte.app.mk
>
> endif
>
Hey Tomasz, there's a whitespace error when applying this patch
Declan
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 0/3] " Tomasz Kulasek
` (2 preceding siblings ...)
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3] mk: Link test app against librte_pmd_ring when needed Tomasz Kulasek
@ 2015-02-13 10:38 ` Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 1/4] test: test.h rework Tomasz Kulasek
` (4 more replies)
3 siblings, 5 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-02-13 10:38 UTC (permalink / raw)
To: dev
This patch series depends of "PMD ring" patches and should be applied after them
to run successfully.
v4 changes
- Adapting to changes in the initialize_eth_header API
- Fix linking problem against librte_pmd_bond.so for shared libraries
- Patchset cleanup for smoother application
v3 changes
- Fix compilation issues for dynamic libraries
- Re-create a series of patches to maintain consistency
v2 changes
- Patch split for better readability
Tomasz Kulasek (4):
test: test.h rework
test: Unit tests for mode 4
mk: Link test app against librte_pmd_ring when needed
pmd_bond: Set routines required by test app global
app/test/Makefile | 16 +
app/test/test.h | 112 +-
app/test/test_link_bonding.c | 2 +-
app/test/test_link_bonding_mode4.c | 1413 ++++++++++++++++++++++++++
lib/librte_pmd_bond/rte_eth_bond_version.map | 2 +
5 files changed, 1498 insertions(+), 47 deletions(-)
create mode 100644 app/test/test_link_bonding_mode4.c
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v4 1/4] test: test.h rework
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Tomasz Kulasek
@ 2015-02-13 10:38 ` Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 2/4] test: Unit tests for mode 4 Tomasz Kulasek
` (3 subsequent siblings)
4 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-02-13 10:38 UTC (permalink / raw)
To: dev
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
app/test/test.h | 112 ++++++++++++++++++++++++++++++++-----------------------
1 file changed, 66 insertions(+), 46 deletions(-)
diff --git a/app/test/test.h b/app/test/test.h
index 896f7db..5450986 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -36,62 +36,79 @@
#include <sys/queue.h>
-#define TEST_ASSERT(cond, msg, ...) do { \
- if (!(cond)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
-} while (0)
+#define TEST_SUCCESS (0)
+#define TEST_FAILED (-1)
+
+/* Before including test.h file you can define
+ * TEST_TRACE_FAILURE(_file, _line, _func) macro to better trace/debug test
+ * failures. Mostly useful in test development phase. */
+#ifndef TEST_TRACE_FAILURE
+# define TEST_TRACE_FAILURE(_file, _line, _func)
+#endif
-#define TEST_ASSERT_EQUAL(a, b, msg, ...) do { \
- if (!(a == b)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT(cond, msg, ...) do { \
+ if (!(cond)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_NOT_EQUAL(a, b, msg, ...) do { \
- if (!(a != b)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_EQUAL(a, b, msg, ...) do { \
+ if (!(a == b)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \
- if (!(val == 0)) { \
- printf("TestCase %s() line %d failed (err %d): " \
- msg "\n", __func__, __LINE__, val, \
- ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NOT_EQUAL(a, b, msg, ...) do { \
+ if (!(a != b)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_FAIL(val, msg, ...) do { \
- if (!(val != 0)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \
+ typeof(val) _val = (val); \
+ if (!(_val == 0)) { \
+ printf("TestCase %s() line %d failed (err %d): " \
+ msg "\n", __func__, __LINE__, _val, \
+ ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
+#define TEST_ASSERT_FAIL(val, msg, ...) do { \
+ if (!(val != 0)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
+} while (0)
-#define TEST_ASSERT_NULL(val, msg, ...) do { \
- if (!(val == NULL)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NULL(val, msg, ...) do { \
+ if (!(val == NULL)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
-#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \
- if (!(val != NULL)) { \
- printf("TestCase %s() line %d failed: " \
- msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
- return -1; \
- } \
+#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \
+ if (!(val != NULL)) { \
+ printf("TestCase %s() line %d failed: " \
+ msg "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \
+ return TEST_FAILED; \
+ } \
} while (0)
struct unit_test_case {
@@ -104,8 +121,11 @@ struct unit_test_case {
#define TEST_CASE(fn) { NULL, NULL, fn, #fn " succeeded", #fn " failed"}
-#define TEST_CASE_ST(setup, teardown, testcase) \
- { setup, teardown, testcase, #testcase " succeeded", \
+#define TEST_CASE_NAMED(name, fn) { NULL, NULL, fn, name " succeeded", \
+ name " failed"}
+
+#define TEST_CASE_ST(setup, teardown, testcase) \
+ { setup, teardown, testcase, #testcase " succeeded", \
#testcase " failed "}
#define TEST_CASES_END() { NULL, NULL, NULL, NULL, NULL }
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v4 2/4] test: Unit tests for mode 4
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 1/4] test: test.h rework Tomasz Kulasek
@ 2015-02-13 10:38 ` Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 3/4] mk: Link test app against librte_pmd_ring when needed Tomasz Kulasek
` (2 subsequent siblings)
4 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-02-13 10:38 UTC (permalink / raw)
To: dev
This patch adds unit tests for mode 4. It is split into separate
file to avoid problems with other modes that does not need to
look into packets payload.
This patch includes also a modification of maximum number of ports
used in their tests for bonding modes 0-3 from 16 to 6.
v4 changes
- Adapting to changes in the initialize_eth_header API
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
app/test/Makefile | 1 +
app/test/test_link_bonding.c | 2 +-
app/test/test_link_bonding_mode4.c | 1413 ++++++++++++++++++++++++++++++++++++
3 files changed, 1415 insertions(+), 1 deletion(-)
create mode 100644 app/test/test_link_bonding_mode4.c
diff --git a/app/test/Makefile b/app/test/Makefile
index 4311f96..ee0e95a 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -129,6 +129,7 @@ SRCS-y += virtual_pmd.c
SRCS-y += packet_burst_generator.c
SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding_mode4.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring.c
SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c
diff --git a/app/test/test_link_bonding.c b/app/test/test_link_bonding.c
index 579ebbf..c5bd78d 100644
--- a/app/test/test_link_bonding.c
+++ b/app/test/test_link_bonding.c
@@ -57,7 +57,7 @@
#include "test.h"
-#define TEST_MAX_NUMBER_OF_PORTS (16)
+#define TEST_MAX_NUMBER_OF_PORTS (6)
#define RX_RING_SIZE 128
#define RX_FREE_THRESH 32
diff --git a/app/test/test_link_bonding_mode4.c b/app/test/test_link_bonding_mode4.c
new file mode 100644
index 0000000..c35129f
--- /dev/null
+++ b/app/test/test_link_bonding_mode4.c
@@ -0,0 +1,1413 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <rte_cycles.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_lcore.h>
+#include <rte_memory.h>
+
+#include <rte_string_fns.h>
+
+#include <rte_eth_ring.h>
+#include <rte_errno.h>
+#include <rte_eth_bond.h>
+#include <rte_eth_bond_8023ad.h>
+
+#include "packet_burst_generator.h"
+
+#include "test.h"
+
+#define SLAVE_COUNT (4)
+
+#define RX_RING_SIZE 128
+#define TX_RING_SIZE 512
+
+#define MBUF_PAYLOAD_SIZE (2048)
+#define MBUF_SIZE (MBUF_PAYLOAD_SIZE + sizeof(struct rte_mbuf) + \
+ RTE_PKTMBUF_HEADROOM)
+#define MBUF_CACHE_SIZE (250)
+#define BURST_SIZE (32)
+
+#define DEFAULT_MBUF_DATA_SIZE (2048)
+#define TEST_RX_DESC_MAX (2048)
+#define TEST_TX_DESC_MAX (2048)
+#define MAX_PKT_BURST (32)
+#define DEF_PKT_BURST (16)
+
+#define BONDED_DEV_NAME ("unit_test_mode4_bond_dev")
+
+#define SLAVE_DEV_NAME_FMT ("unit_test_mode4_slave_%d")
+#define SLAVE_RX_QUEUE_FMT ("unit_test_mode4_slave_%d_rx")
+#define SLAVE_TX_QUEUE_FMT ("unit_test_mode4_slave_%d_tx")
+
+#define INVALID_SOCKET_ID (-1)
+#define INVALID_PORT_ID (0xFF)
+#define INVALID_BONDING_MODE (-1)
+
+static const struct ether_addr slave_mac_default = {
+ { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 }
+};
+
+static const struct ether_addr parnter_mac_default = {
+ { 0x22, 0xBB, 0xFF, 0xBB, 0x00, 0x00 }
+};
+
+static const struct ether_addr parnter_system = {
+ { 0x33, 0xFF, 0xBB, 0xFF, 0x00, 0x00 }
+};
+
+static const struct ether_addr slow_protocol_mac_addr = {
+ { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 }
+};
+
+struct slave_conf {
+ struct rte_ring *rx_queue;
+ struct rte_ring *tx_queue;
+ uint8_t port_id;
+ uint8_t bonded : 1;
+
+ uint8_t lacp_parnter_state;
+};
+
+struct ether_vlan_hdr {
+ struct ether_hdr pkt_eth_hdr;
+ struct vlan_hdr vlan_hdr;
+};
+
+struct link_bonding_unittest_params {
+ uint8_t bonded_port_id;
+ struct slave_conf slave_ports[SLAVE_COUNT];
+
+ struct rte_mempool *mbuf_pool;
+};
+
+#define TEST_DEFAULT_SLAVE_COUNT RTE_DIM(test_params.slave_ports)
+#define TEST_RX_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_TX_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_MARKER_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_EXPIRED_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+#define TEST_PROMISC_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT
+
+static struct link_bonding_unittest_params test_params = {
+ .bonded_port_id = INVALID_PORT_ID,
+ .slave_ports = { [0 ... SLAVE_COUNT - 1] = { .port_id = INVALID_PORT_ID} },
+
+ .mbuf_pool = NULL,
+};
+
+static struct rte_eth_conf default_pmd_conf = {
+ .rxmode = {
+ .mq_mode = ETH_MQ_RX_NONE,
+ .max_rx_pkt_len = ETHER_MAX_LEN,
+ .split_hdr_size = 0,
+ .header_split = 0, /**< Header Split disabled */
+ .hw_ip_checksum = 0, /**< IP checksum offload enabled */
+ .hw_vlan_filter = 0, /**< VLAN filtering disabled */
+ .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /**< CRC stripped by hardware */
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+ .lpbk_mode = 0,
+};
+
+#define FOR_EACH(_i, _item, _array, _size) \
+ for (_i = 0, _item = &_array[0]; _i < _size && (_item = &_array[_i]); _i++)
+
+/* Macro for iterating over every port that can be used as a slave
+ * in this test.
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ */
+#define FOR_EACH_PORT(_i, _port) \
+ FOR_EACH(_i, _port, test_params.slave_ports, \
+ RTE_DIM(test_params.slave_ports))
+
+/* Macro for iterating over every port that can be used as a slave
+ * in this test and satisfy given condition.
+ *
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ * _condition condition that need to be checked
+ */
+#define FOR_EACH_PORT_IF(_i, _port, _condition) FOR_EACH_PORT((_i), (_port)) \
+ if (!!(_condition))
+
+/* Macro for iterating over every port that is currently a slave of a bonded
+ * device.
+ * _i variable used as an index in test_params->slave_ports
+ * _slave pointer to &test_params->slave_ports[_idx]
+ * */
+#define FOR_EACH_SLAVE(_i, _slave) \
+ FOR_EACH_PORT_IF(_i, _slave, (_slave)->bonded != 0)
+
+/*
+ * Returns packets from slaves TX queue.
+ * slave slave port
+ * buffer for packets
+ * size size of buffer
+ * return number of packets or negative error number
+ */
+static int
+slave_get_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_ring_dequeue_burst(slave->tx_queue, (void **)buf, size);
+}
+
+/*
+ * Injects given packets into slaves RX queue.
+ * slave slave port
+ * buffer for packets
+ * size number of packets to be injected
+ * return number of queued packets or negative error number
+ */
+static int
+slave_put_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_ring_enqueue_burst(slave->rx_queue, (void **)buf, size);
+}
+
+static uint16_t
+bond_rx(struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_eth_rx_burst(test_params.bonded_port_id, 0, buf, size);
+}
+
+static uint16_t
+bond_tx(struct rte_mbuf **buf, uint16_t size)
+{
+ return rte_eth_tx_burst(test_params.bonded_port_id, 0, buf, size);
+}
+
+static void
+free_pkts(struct rte_mbuf **pkts, uint16_t count)
+{
+ uint16_t i;
+
+ for (i = 0; i < count; i++) {
+ if (pkts[i] != NULL)
+ rte_pktmbuf_free(pkts[i]);
+ }
+}
+
+static int
+configure_ethdev(uint8_t port_id, uint8_t start)
+{
+ TEST_ASSERT(rte_eth_dev_configure(port_id, 1, 1, &default_pmd_conf) == 0,
+ "Failed to configure device %u", port_id);
+
+ TEST_ASSERT(rte_eth_rx_queue_setup(port_id, 0, RX_RING_SIZE,
+ rte_eth_dev_socket_id(port_id), NULL, test_params.mbuf_pool) == 0,
+ "Failed to setup rx queue.");
+
+ TEST_ASSERT(rte_eth_tx_queue_setup(port_id, 0, TX_RING_SIZE,
+ rte_eth_dev_socket_id(port_id), NULL) == 0,
+ "Failed to setup tx queue.");
+
+ if (start) {
+ TEST_ASSERT(rte_eth_dev_start(port_id) == 0,
+ "Failed to start device (%d).", port_id);
+ }
+ return 0;
+}
+
+static int
+add_slave(struct slave_conf *slave, uint8_t start)
+{
+ struct ether_addr addr, addr_check;
+
+ /* Some sanity check */
+ RTE_VERIFY(test_params.slave_ports <= slave &&
+ slave - test_params.slave_ports < (int)RTE_DIM(test_params.slave_ports));
+ RTE_VERIFY(slave->bonded == 0);
+ RTE_VERIFY(slave->port_id != INVALID_PORT_ID);
+
+ ether_addr_copy(&slave_mac_default, &addr);
+ addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+
+ rte_eth_dev_mac_addr_remove(slave->port_id, &addr);
+
+ TEST_ASSERT_SUCCESS(rte_eth_dev_mac_addr_add(slave->port_id, &addr, 0),
+ "Failed to set slave MAC address");
+
+ TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bonded_port_id,
+ slave->port_id),
+ "Failed to add slave (idx=%u, id=%u) to bonding (id=%u)",
+ (uint8_t)(slave - test_params.slave_ports), slave->port_id,
+ test_params.bonded_port_id);
+
+ slave->bonded = 1;
+ if (start) {
+ TEST_ASSERT_SUCCESS(rte_eth_dev_start(slave->port_id),
+ "Failed to start slave %u", slave->port_id);
+ }
+
+ rte_eth_macaddr_get(slave->port_id, &addr_check);
+ TEST_ASSERT_EQUAL(is_same_ether_addr(&addr, &addr_check), 1,
+ "Slave MAC address is not as expected");
+
+ RTE_VERIFY(slave->lacp_parnter_state == 0);
+ return 0;
+}
+
+static int
+remove_slave(struct slave_conf *slave)
+{
+ ptrdiff_t slave_idx = slave - test_params.slave_ports;
+
+ RTE_VERIFY(test_params.slave_ports <= slave &&
+ slave_idx < (ptrdiff_t)RTE_DIM(test_params.slave_ports));
+
+ RTE_VERIFY(slave->bonded == 1);
+ RTE_VERIFY(slave->port_id != INVALID_PORT_ID);
+
+ TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0,
+ "Slave %u tx queue not empty while removing from bonding.",
+ slave->port_id);
+
+ TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0,
+ "Slave %u tx queue not empty while removing from bonding.",
+ slave->port_id);
+
+ TEST_ASSERT_EQUAL(rte_eth_bond_slave_remove(test_params.bonded_port_id,
+ slave->port_id), 0,
+ "Failed to remove slave (idx=%u, id=%u) from bonding (id=%u)",
+ (uint8_t)slave_idx, slave->port_id,
+ test_params.bonded_port_id);
+
+ slave->bonded = 0;
+ slave->lacp_parnter_state = 0;
+ return 0;
+}
+
+static int
+initialize_bonded_device_with_slaves(uint8_t slave_count, uint8_t start)
+{
+ uint8_t i;
+
+ RTE_VERIFY(test_params.bonded_port_id != INVALID_PORT_ID);
+
+ for (i = 0; i < slave_count; i++) {
+ TEST_ASSERT_SUCCESS(add_slave(&test_params.slave_ports[i], 1),
+ "Failed to add port %u to bonded device.\n",
+ test_params.slave_ports[i].port_id);
+ }
+
+ /* Reset mode 4 configuration */
+ rte_eth_bond_8023ad_setup(test_params.bonded_port_id, NULL);
+ rte_eth_promiscuous_disable(test_params.bonded_port_id);
+
+ if (start)
+ TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bonded_port_id),
+ "Failed to start bonded device");
+
+ return TEST_SUCCESS;
+}
+
+static int
+remove_slaves_and_stop_bonded_device(void)
+{
+ struct slave_conf *slave;
+ int retval;
+ uint8_t slaves[RTE_MAX_ETHPORTS];
+ uint8_t i;
+
+ rte_eth_dev_stop(test_params.bonded_port_id);
+
+ FOR_EACH_SLAVE(i, slave)
+ remove_slave(slave);
+
+ retval = rte_eth_bond_slaves_get(test_params.bonded_port_id, slaves,
+ RTE_DIM(slaves));
+
+ TEST_ASSERT_EQUAL(retval, 0,
+ "Expected bonded device %u have 0 slaves but returned %d.",
+ test_params.bonded_port_id, retval);
+
+ FOR_EACH_PORT(i, slave) {
+ rte_eth_dev_stop(slave->port_id);
+
+ TEST_ASSERT(slave->bonded == 0,
+ "Port id=%u is still marked as enslaved.", slave->port_id);
+ }
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_setup(void)
+{
+ int retval, nb_mbuf_per_pool;
+ char name[RTE_ETH_NAME_MAX_LEN];
+ struct slave_conf *port;
+ const uint8_t socket_id = rte_socket_id();
+ uint8_t i;
+
+ if (test_params.mbuf_pool == NULL) {
+ nb_mbuf_per_pool = TEST_RX_DESC_MAX + DEF_PKT_BURST +
+ TEST_TX_DESC_MAX + MAX_PKT_BURST;
+ test_params.mbuf_pool = rte_mempool_create("TEST_MODE4",
+ nb_mbuf_per_pool, MBUF_SIZE, MBUF_CACHE_SIZE,
+ sizeof(struct rte_pktmbuf_pool_private),
+ rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
+ socket_id, 0);
+
+ TEST_ASSERT(test_params.mbuf_pool != NULL,
+ "rte_mempool_create failed\n");
+ }
+
+ /* Create / initialize ring eth devs. */
+ FOR_EACH_PORT(i, port) {
+ port = &test_params.slave_ports[i];
+
+ if (port->rx_queue == NULL) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_RX_QUEUE_FMT, i);
+ TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long");
+ port->rx_queue = rte_ring_create(name, RX_RING_SIZE, socket_id, 0);
+ TEST_ASSERT(port->rx_queue != NULL,
+ "Failed to allocate rx ring '%s': %s", name,
+ rte_strerror(rte_errno));
+ }
+
+ if (port->tx_queue == NULL) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_TX_QUEUE_FMT, i);
+ TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long");
+ port->tx_queue = rte_ring_create(name, TX_RING_SIZE, socket_id, 0);
+ TEST_ASSERT_NOT_NULL(port->tx_queue,
+ "Failed to allocate tx ring '%s': %s", name,
+ rte_strerror(rte_errno));
+ }
+
+ if (port->port_id == INVALID_PORT_ID) {
+ retval = snprintf(name, RTE_DIM(name), SLAVE_DEV_NAME_FMT, i);
+ TEST_ASSERT(retval < (int)RTE_DIM(name) - 1, "Name too long");
+ retval = rte_eth_from_rings(name, &port->rx_queue, 1,
+ &port->tx_queue, 1, socket_id);
+ TEST_ASSERT(retval >= 0,
+ "Failed to create ring ethdev '%s'\n", name);
+
+ port->port_id = rte_eth_dev_count() - 1;
+ }
+
+ retval = configure_ethdev(port->port_id, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to configure virtual ethdev %s\n",
+ name);
+ }
+
+ if (test_params.bonded_port_id == INVALID_PORT_ID) {
+ retval = rte_eth_bond_create(BONDED_DEV_NAME, BONDING_MODE_8023AD,
+ socket_id);
+
+ TEST_ASSERT(retval >= 0, "Failed to create bonded ethdev %s",
+ BONDED_DEV_NAME);
+
+ test_params.bonded_port_id = retval;
+ TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bonded_port_id, 0),
+ "Failed to configure bonded ethdev %s", BONDED_DEV_NAME);
+ } else if (rte_eth_bond_mode_get(test_params.bonded_port_id) !=
+ BONDING_MODE_8023AD) {
+ TEST_ASSERT(rte_eth_bond_mode_set(test_params.bonded_port_id,
+ BONDING_MODE_8023AD) == 0,
+ "Failed to set ethdev %d to mode %d",
+ test_params.bonded_port_id, BONDING_MODE_8023AD);
+ }
+
+ return 0;
+}
+
+static int
+testsuite_teardown(void)
+{
+ struct slave_conf *port;
+ uint8_t i;
+
+ /* Only stop ports.
+ * Any cleanup/reset state is done when particular test is
+ * started. */
+
+ rte_eth_dev_stop(test_params.bonded_port_id);
+
+ FOR_EACH_PORT(i, port)
+ rte_eth_dev_stop(port->port_id);
+
+ return 0;
+}
+
+/*
+ * Check if given LACP packet. If it is, make make replay packet to force
+ * COLLECTING state.
+ * return 0 when pkt is LACP frame, 1 if it is not slow frame, 2 if it is slow
+ * frame but not LACP
+ */
+static int
+make_lacp_reply(struct slave_conf *slave, struct rte_mbuf *pkt)
+{
+ struct ether_hdr *hdr;
+ struct slow_protocol_frame *slow_hdr;
+ struct lacpdu *lacp;
+
+ /* look for LACP */
+ hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+ if (hdr->ether_type != rte_cpu_to_be_16(ETHER_TYPE_SLOW))
+ return 1;
+
+ slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *);
+ /* ignore packets of other types */
+ if (slow_hdr->slow_protocol.subtype != SLOW_SUBTYPE_LACP)
+ return 2;
+
+ slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *);
+
+ /* Change source address to partner address */
+ ether_addr_copy(&parnter_mac_default, &slow_hdr->eth_hdr.s_addr);
+ slow_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+
+ lacp = (struct lacpdu *) &slow_hdr->slow_protocol;
+ /* Save last received state */
+ slave->lacp_parnter_state = lacp->actor.state;
+ /* Change it into LACP replay by matching parameters. */
+ memcpy(&lacp->partner.port_params, &lacp->actor.port_params,
+ sizeof(struct port_params));
+
+ lacp->partner.state = lacp->actor.state;
+
+ ether_addr_copy(&parnter_system, &lacp->actor.port_params.system);
+ lacp->actor.state = STATE_LACP_ACTIVE |
+ STATE_SYNCHRONIZATION |
+ STATE_AGGREGATION |
+ STATE_COLLECTING |
+ STATE_DISTRIBUTING;
+
+ return 0;
+}
+
+/*
+ * Reads packets from given slave, search for LACP packet and reply them.
+ *
+ * Receives burst of packets from slave. Looks for LACP packet. Drops
+ * all other packets. Prepares response LACP and sends it back.
+ *
+ * return number of LACP received and replied, -1 on error.
+ */
+static int
+bond_handshake_reply(struct slave_conf *slave)
+{
+ int retval;
+ struct rte_mbuf *rx_buf[MAX_PKT_BURST];
+ struct rte_mbuf *lacp_tx_buf[MAX_PKT_BURST];
+ uint16_t lacp_tx_buf_cnt = 0, i;
+
+ retval = slave_get_pkts(slave, rx_buf, RTE_DIM(rx_buf));
+ TEST_ASSERT(retval >= 0, "Getting slave %u packets failed.",
+ slave->port_id);
+
+ for (i = 0; i < (uint16_t)retval; i++) {
+ if (make_lacp_reply(slave, rx_buf[i]) == 0) {
+ /* reply with actor's LACP */
+ lacp_tx_buf[lacp_tx_buf_cnt++] = rx_buf[i];
+ } else
+ rte_pktmbuf_free(rx_buf[i]);
+ }
+
+ if (lacp_tx_buf_cnt == 0)
+ return 0;
+
+ retval = slave_put_pkts(slave, lacp_tx_buf, lacp_tx_buf_cnt);
+ if (retval <= lacp_tx_buf_cnt) {
+ /* retval might be negative */
+ for (i = RTE_MAX(0, retval); retval < lacp_tx_buf_cnt; retval++)
+ rte_pktmbuf_free(lacp_tx_buf[i]);
+ }
+
+ TEST_ASSERT_EQUAL(retval, lacp_tx_buf_cnt,
+ "Failed to equeue lacp packets into slave %u tx queue.",
+ slave->port_id);
+
+ return lacp_tx_buf_cnt;
+}
+
+/*
+ * Function check if given slave tx queue contains packets that make mode 4
+ * handshake complete. It will drain slave queue.
+ * return 0 if handshake not completed, 1 if handshake was complete,
+ */
+static int
+bond_handshake_done(struct slave_conf *slave)
+{
+ const uint8_t expected_state = STATE_LACP_ACTIVE | STATE_SYNCHRONIZATION |
+ STATE_AGGREGATION | STATE_COLLECTING | STATE_DISTRIBUTING;
+
+ return slave->lacp_parnter_state == expected_state;
+}
+
+static unsigned
+bond_get_update_timeout_ms(void)
+{
+ struct rte_eth_bond_8023ad_conf conf;
+
+ rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf);
+ return conf.update_timeout_ms;
+}
+
+/*
+ * Exchanges LACP packets with partner to achieve dynamic port configuration.
+ * return TEST_SUCCESS if initial handshake succeed, TEST_FAILED otherwise.
+ */
+static int
+bond_handshake(void)
+{
+ struct slave_conf *slave;
+ struct rte_mbuf *buf[MAX_PKT_BURST];
+ uint16_t nb_pkts;
+ uint8_t all_slaves_done, i, j;
+ uint8_t status[RTE_DIM(test_params.slave_ports)] = { 0 };
+ const unsigned delay = bond_get_update_timeout_ms();
+
+ /* Exchange LACP frames */
+ all_slaves_done = 0;
+ for (i = 0; i < 30 && all_slaves_done == 0; ++i) {
+ rte_delay_ms(delay);
+
+ all_slaves_done = 1;
+ FOR_EACH_SLAVE(j, slave) {
+ /* If response already send, skip slave */
+ if (status[j] != 0)
+ continue;
+
+ if (bond_handshake_reply(slave) < 0) {
+ all_slaves_done = 0;
+ break;
+ }
+
+ status[j] = bond_handshake_done(slave);
+ if (status[j] == 0)
+ all_slaves_done = 0;
+ }
+
+ nb_pkts = bond_tx(NULL, 0);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets transmitted unexpectedly");
+
+ nb_pkts = bond_rx(buf, RTE_DIM(buf));
+ free_pkts(buf, nb_pkts);
+ TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets received unexpectedly");
+ }
+ /* If response didn't send - report failure */
+ TEST_ASSERT_EQUAL(all_slaves_done, 1, "Bond handshake failed\n");
+
+ /* If flags doesn't match - report failure */
+ return all_slaves_done = 1 ? TEST_SUCCESS : TEST_FAILED;
+}
+
+#define TEST_LACP_SLAVE_COUT RTE_DIM(test_params.slave_ports)
+static int
+test_mode4_lacp(void)
+{
+ int retval;
+
+ retval = initialize_bonded_device_with_slaves(TEST_LACP_SLAVE_COUT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ /* Test LACP handshake function */
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+generate_packets(struct ether_addr *src_mac,
+ struct ether_addr *dst_mac, uint16_t count, struct rte_mbuf **buf)
+{
+ uint16_t pktlen = PACKET_BURST_GEN_PKT_LEN;
+ uint8_t vlan_enable = 0;
+ uint16_t vlan_id = 0;
+ uint8_t ip4_type = 1; /* 0 - ipv6 */
+
+ uint16_t src_port = 10, dst_port = 20;
+
+ uint32_t ip_src[4] = { [0 ... 2] = 0xDEADBEEF, [3] = IPv4(192, 168, 0, 1) };
+ uint32_t ip_dst[4] = { [0 ... 2] = 0xFEEDFACE, [3] = IPv4(192, 168, 0, 2) };
+
+ struct ether_hdr pkt_eth_hdr;
+ struct udp_hdr pkt_udp_hdr;
+ union {
+ struct ipv4_hdr v4;
+ struct ipv6_hdr v6;
+ } pkt_ip_hdr;
+
+ int retval;
+
+ initialize_eth_header(&pkt_eth_hdr, src_mac, dst_mac, ip4_type,
+ vlan_enable, vlan_id);
+
+ if (ip4_type)
+ initialize_ipv4_header(&pkt_ip_hdr.v4, ip_src[3], ip_dst[3], pktlen);
+ else
+ initialize_ipv6_header(&pkt_ip_hdr.v6, (uint8_t *)ip_src,
+ (uint8_t *)&ip_dst, pktlen);
+
+ initialize_udp_header(&pkt_udp_hdr, src_port, dst_port, 16);
+
+ retval = generate_packet_burst(test_params.mbuf_pool, buf,
+ &pkt_eth_hdr, vlan_enable, &pkt_ip_hdr, 1, &pkt_udp_hdr,
+ count, pktlen, 1);
+
+ if (retval > 0 && retval != count)
+ free_pkts(&buf[count - retval], retval);
+
+ TEST_ASSERT_EQUAL(retval, count, "Failed to generate %u packets",
+ count);
+
+ return count;
+}
+
+static int
+generate_and_put_packets(struct slave_conf *slave, struct ether_addr *src_mac,
+ struct ether_addr *dst_mac, uint16_t count)
+{
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+
+ retval = generate_packets(src_mac, dst_mac, count, pkts);
+ if (retval != (int)count)
+ return retval;
+
+ retval = slave_put_pkts(slave, pkts, count);
+ if (retval > 0 && retval != count)
+ free_pkts(&pkts[retval], count - retval);
+
+ TEST_ASSERT_EQUAL(retval, count,
+ "Failed to enqueue packets into slave %u RX queue", slave->port_id);
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_rx(void)
+{
+ struct slave_conf *slave;
+ uint16_t i, j;
+
+ uint16_t expected_pkts_cnt;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+ unsigned delay;
+
+ struct ether_hdr *hdr;
+
+ struct ether_addr src_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } };
+ struct ether_addr dst_mac;
+ struct ether_addr bonded_mac;
+
+ retval = initialize_bonded_device_with_slaves(TEST_PROMISC_SLAVE_COUNT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac);
+ ether_addr_copy(&bonded_mac, &dst_mac);
+
+ /* Assert that dst address is not bonding address */
+ dst_mac.addr_bytes[0]++;
+
+ /* First try with promiscuous mode enabled.
+ * Add 2 packets to each slave. First with bonding MAC address, second with
+ * different. Check if we received all of them. */
+ rte_eth_promiscuous_enable(test_params.bonded_port_id);
+
+ expected_pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ /* Expect 2 packets per slave */
+ expected_pkts_cnt += 2;
+ }
+
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval == expected_pkts_cnt) {
+ int cnt[2] = { 0, 0 };
+
+ for (i = 0; i < expected_pkts_cnt; i++) {
+ hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+ cnt[is_same_ether_addr(&hdr->d_addr, &bonded_mac)]++;
+ }
+
+ free_pkts(pkts, expected_pkts_cnt);
+
+ /* For division by 2 expected_pkts_cnt must be even */
+ RTE_VERIFY((expected_pkts_cnt & 1) == 0);
+ TEST_ASSERT(cnt[0] == expected_pkts_cnt / 2 &&
+ cnt[1] == expected_pkts_cnt / 2,
+ "Expected %u packets with the same MAC and %u with different but "
+ "got %u with the same and %u with diffrent MAC",
+ expected_pkts_cnt / 2, expected_pkts_cnt / 2, cnt[1], cnt[0]);
+ } else if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, expected_pkts_cnt,
+ "Expected %u packets but received only %d", expected_pkts_cnt, retval);
+
+ /* Now, disable promiscuous mode. When promiscuous mode is disabled we
+ * expect to receive only packets that are directed to bonding port. */
+ rte_eth_promiscuous_disable(test_params.bonded_port_id);
+
+ expected_pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u",
+ slave->port_id);
+
+ /* Expect only one packet per slave */
+ expected_pkts_cnt += 1;
+ }
+
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval == expected_pkts_cnt) {
+ int eq_cnt = 0;
+
+ for (i = 0; i < expected_pkts_cnt; i++) {
+ hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *);
+ eq_cnt += is_same_ether_addr(&hdr->d_addr, &bonded_mac);
+ }
+
+ free_pkts(pkts, expected_pkts_cnt);
+ TEST_ASSERT_EQUAL(eq_cnt, expected_pkts_cnt, "Packet address mismatch");
+ } else if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, expected_pkts_cnt,
+ "Expected %u packets but received only %d", expected_pkts_cnt, retval);
+
+ /* Link down test: simulate link down for first slave. */
+ delay = bond_get_update_timeout_ms();
+
+ uint8_t slave_down_id = INVALID_PORT_ID;
+
+ /* Find first slave and make link down on it*/
+ FOR_EACH_SLAVE(i, slave) {
+ rte_eth_dev_set_link_down(slave->port_id);
+ slave_down_id = slave->port_id;
+ break;
+ }
+
+ RTE_VERIFY(slave_down_id != INVALID_PORT_ID);
+
+ /* Give some time to rearrange bonding */
+ for (i = 0; i < 3; i++) {
+ rte_delay_ms(delay);
+ bond_handshake();
+ }
+
+ TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed");
+
+ /* Put packet to each slave */
+ FOR_EACH_SLAVE(i, slave) {
+ void *pkt = NULL;
+
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+ retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst.");
+
+ src_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id;
+ retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst.");
+
+ retval = bond_rx(pkts, RTE_DIM(pkts));
+
+ /* Clean anything */
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ while (rte_ring_dequeue(slave->rx_queue, (void **)&pkt) == 0)
+ rte_pktmbuf_free(pkt);
+
+ if (slave_down_id == slave->port_id)
+ TEST_ASSERT_EQUAL(retval, 0, "Packets received unexpectedly.");
+ else
+ TEST_ASSERT_NOT_EQUAL(retval, 0,
+ "Expected to receive some packets on slave %u.",
+ slave->port_id);
+ rte_eth_dev_start(slave->port_id);
+
+ for (j = 0; j < 5; j++) {
+ TEST_ASSERT(bond_handshake_reply(slave) >= 0,
+ "Handshake after link up");
+
+ if (bond_handshake_done(slave) == 1)
+ break;
+ }
+
+ TEST_ASSERT(j < 5, "Failed to agregate slave after link up");
+ }
+
+ remove_slaves_and_stop_bonded_device();
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_tx_burst(void)
+{
+ struct slave_conf *slave;
+ uint16_t i, j;
+
+ uint16_t exp_pkts_cnt, pkts_cnt = 0;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ int retval;
+ unsigned delay;
+
+ struct ether_addr dst_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } };
+ struct ether_addr bonded_mac;
+
+ retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac);
+
+ /* Prepare burst */
+ for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) {
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt;
+ retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]);
+
+ if (retval != 1)
+ free_pkts(pkts, pkts_cnt);
+
+ TEST_ASSERT_EQUAL(retval, 1, "Failed to generate packet %u", pkts_cnt);
+ }
+ exp_pkts_cnt = pkts_cnt;
+
+ /* Transmit packets on bonded device */
+ retval = bond_tx(pkts, pkts_cnt);
+ if (retval > 0 && retval < pkts_cnt)
+ free_pkts(&pkts[retval], pkts_cnt - retval);
+
+ TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed");
+
+ /* Check if packets were transmitted properly. Every slave should have
+ * at least one packet, and sum must match. Under normal operation
+ * there should be no LACP nor MARKER frames. */
+ pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ uint16_t normal_cnt, slow_cnt;
+
+ retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts));
+ normal_cnt = 0;
+ slow_cnt = 0;
+
+ for (j = 0; j < retval; j++) {
+ if (make_lacp_reply(slave, pkts[j]) == 1)
+ normal_cnt++;
+ else
+ slow_cnt++;
+ }
+
+ free_pkts(pkts, normal_cnt + slow_cnt);
+ TEST_ASSERT_EQUAL(slow_cnt, 0,
+ "slave %u unexpectedly transmitted %d SLOW packets", slave->port_id,
+ slow_cnt);
+
+ TEST_ASSERT_NOT_EQUAL(normal_cnt, 0,
+ "slave %u did not transmitted any packets", slave->port_id);
+
+ pkts_cnt += normal_cnt;
+ }
+
+ TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt,
+ "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt);
+
+ /* Link down test:
+ * simulate link down for first slave. */
+ delay = bond_get_update_timeout_ms();
+
+ uint8_t slave_down_id = INVALID_PORT_ID;
+
+ FOR_EACH_SLAVE(i, slave) {
+ rte_eth_dev_set_link_down(slave->port_id);
+ slave_down_id = slave->port_id;
+ break;
+ }
+
+ RTE_VERIFY(slave_down_id != INVALID_PORT_ID);
+
+ /* Give some time to rearrange bonding. */
+ for (i = 0; i < 3; i++) {
+ bond_handshake();
+ rte_delay_ms(delay);
+ }
+
+ TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed");
+
+ /* Prepare burst. */
+ for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) {
+ dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt;
+ retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]);
+
+ if (retval != 1)
+ free_pkts(pkts, pkts_cnt);
+
+ TEST_ASSERT_EQUAL(retval, 1, "Failed to generate test packet %u",
+ pkts_cnt);
+ }
+ exp_pkts_cnt = pkts_cnt;
+
+ /* Transmit packets on bonded device. */
+ retval = bond_tx(pkts, pkts_cnt);
+ if (retval > 0 && retval < pkts_cnt)
+ free_pkts(&pkts[retval], pkts_cnt - retval);
+
+ TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed");
+
+ /* Check if packets was transmitted properly. Every slave should have
+ * at least one packet, and sum must match. Under normal operation
+ * there should be no LACP nor MARKER frames. */
+ pkts_cnt = 0;
+ FOR_EACH_SLAVE(i, slave) {
+ uint16_t normal_cnt, slow_cnt;
+
+ retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts));
+ normal_cnt = 0;
+ slow_cnt = 0;
+
+ for (j = 0; j < retval; j++) {
+ if (make_lacp_reply(slave, pkts[j]) == 1)
+ normal_cnt++;
+ else
+ slow_cnt++;
+ }
+
+ free_pkts(pkts, normal_cnt + slow_cnt);
+
+ if (slave_down_id == slave->port_id) {
+ TEST_ASSERT_EQUAL(normal_cnt + slow_cnt, 0,
+ "slave %u enexpectedly transmitted %u packets",
+ normal_cnt + slow_cnt, slave->port_id);
+ } else {
+ TEST_ASSERT_EQUAL(slow_cnt, 0,
+ "slave %u unexpectedly transmitted %d SLOW packets",
+ slave->port_id, slow_cnt);
+
+ TEST_ASSERT_NOT_EQUAL(normal_cnt, 0,
+ "slave %u did not transmitted any packets", slave->port_id);
+ }
+
+ pkts_cnt += normal_cnt;
+ }
+
+ TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt,
+ "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt);
+
+ return remove_slaves_and_stop_bonded_device();
+}
+
+static void
+init_marker(struct rte_mbuf *pkt, struct slave_conf *slave)
+{
+ struct marker_header *marker_hdr = rte_pktmbuf_mtod(pkt,
+ struct marker_header *);
+
+ /* Copy multicast destination address */
+ ether_addr_copy(&slow_protocol_mac_addr, &marker_hdr->eth_hdr.d_addr);
+
+ /* Init source address */
+ ether_addr_copy(&parnter_mac_default, &marker_hdr->eth_hdr.s_addr);
+ marker_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN-1] = slave->port_id;
+
+ marker_hdr->eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_SLOW);
+
+ marker_hdr->marker.subtype = SLOW_SUBTYPE_MARKER;
+ marker_hdr->marker.version_number = 1;
+ marker_hdr->marker.tlv_type_marker = MARKER_TLV_TYPE_INFO;
+ marker_hdr->marker.info_length =
+ offsetof(struct marker, reserved_90) -
+ offsetof(struct marker, requester_port);
+ RTE_VERIFY(marker_hdr->marker.info_length == 16);
+ marker_hdr->marker.requester_port = slave->port_id + 1;
+ marker_hdr->marker.tlv_type_terminator = TLV_TYPE_TERMINATOR_INFORMATION;
+ marker_hdr->marker.terminator_length = 0;
+}
+
+static int
+test_mode4_marker(void)
+{
+ struct slave_conf *slave;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ struct rte_mbuf *marker_pkt;
+ struct marker_header *marker_hdr;
+
+ unsigned delay;
+ int retval;
+ uint16_t nb_pkts;
+ uint8_t i, j;
+ const uint16_t ethtype_slow_be = rte_be_to_cpu_16(ETHER_TYPE_SLOW);
+
+ retval = initialize_bonded_device_with_slaves(TEST_MARKER_SLAVE_COUT, 1);
+ TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device");
+
+ /* Test LACP handshake function */
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ delay = bond_get_update_timeout_ms();
+ FOR_EACH_SLAVE(i, slave) {
+ marker_pkt = rte_pktmbuf_alloc(test_params.mbuf_pool);
+ TEST_ASSERT_NOT_NULL(marker_pkt, "Failed to allocate marker packet");
+ init_marker(marker_pkt, slave);
+
+ retval = slave_put_pkts(slave, &marker_pkt, 1);
+ if (retval != 1)
+ rte_pktmbuf_free(marker_pkt);
+
+ TEST_ASSERT_EQUAL(retval, 1,
+ "Failed to send marker packet to slave %u", slave->port_id);
+
+ for (j = 0; j < 20; ++j) {
+ rte_delay_ms(delay);
+ retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts,
+ RTE_DIM(pkts));
+
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 0, "Received packets unexpectedly");
+
+ retval = rte_eth_tx_burst(test_params.bonded_port_id, 0, NULL, 0);
+ TEST_ASSERT_EQUAL(retval, 0,
+ "Requested TX of 0 packets but %d transmitted", retval);
+
+ /* Check if LACP packet was send by state machines
+ First and only packet must be a maker response */
+ retval = slave_get_pkts(slave, pkts, MAX_PKT_BURST);
+ if (retval == 0)
+ continue;
+ if (retval > 1)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 1, "failed to get slave packets");
+ nb_pkts = retval;
+
+ marker_hdr = rte_pktmbuf_mtod(pkts[0], struct marker_header *);
+ /* Check if it's slow packet*/
+ if (marker_hdr->eth_hdr.ether_type != ethtype_slow_be)
+ retval = -1;
+ /* Check if it's marker packet */
+ else if (marker_hdr->marker.subtype != SLOW_SUBTYPE_MARKER)
+ retval = -2;
+ else if (marker_hdr->marker.tlv_type_marker != MARKER_TLV_TYPE_RESP)
+ retval = -3;
+
+ free_pkts(pkts, nb_pkts);
+
+ TEST_ASSERT_NOT_EQUAL(retval, -1, "Unexpected protocol type");
+ TEST_ASSERT_NOT_EQUAL(retval, -2, "Unexpected sub protocol type");
+ TEST_ASSERT_NOT_EQUAL(retval, -3, "Unexpected marker type");
+ break;
+ }
+
+ TEST_ASSERT(j < 20, "Marker response not found");
+ }
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_expired(void)
+{
+ struct slave_conf *slave, *exp_slave = NULL;
+ struct rte_mbuf *pkts[MAX_PKT_BURST];
+ struct rte_mbuf *pkt = NULL;
+ int retval;
+ uint32_t old_delay;
+
+ uint8_t i;
+ uint16_t j;
+
+ struct rte_eth_bond_8023ad_conf conf;
+
+ retval = initialize_bonded_device_with_slaves(TEST_EXPIRED_SLAVE_COUNT, 1);
+ /* Set custom timeouts to make test last shorter. */
+ rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf);
+ conf.fast_periodic_ms = 100;
+ conf.slow_periodic_ms = 600;
+ conf.short_timeout_ms = 300;
+ conf.long_timeout_ms = 900;
+ conf.aggregate_wait_timeout_ms = 200;
+ conf.tx_period_ms = 100;
+ old_delay = conf.update_timeout_ms;
+ conf.update_timeout_ms = 10;
+ rte_eth_bond_8023ad_setup(test_params.bonded_port_id, &conf);
+
+ /* Wait for new settings to be applied. */
+ for (i = 0; i < old_delay/conf.update_timeout_ms * 2; i++) {
+ FOR_EACH_SLAVE(j, slave)
+ bond_handshake_reply(slave);
+
+ rte_delay_ms(conf.update_timeout_ms);
+ }
+
+ retval = bond_handshake();
+ TEST_ASSERT_SUCCESS(retval, "Initial handshake failed");
+
+ /* Find first slave */
+ FOR_EACH_SLAVE(i, slave) {
+ exp_slave = slave;
+ break;
+ }
+
+ RTE_VERIFY(exp_slave != NULL);
+
+ /* When one of partners do not send or respond to LACP frame in
+ * conf.long_timeout_ms time, internal state machines should detect this
+ * and transit to expired state. */
+ for (j = 0; j < conf.long_timeout_ms/conf.update_timeout_ms + 2; j++) {
+ rte_delay_ms(conf.update_timeout_ms);
+
+ retval = bond_tx(NULL, 0);
+ TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets",
+ retval);
+
+ FOR_EACH_SLAVE(i, slave) {
+ retval = bond_handshake_reply(slave);
+ TEST_ASSERT(retval >= 0, "Handshake failed");
+
+ /* Remove replay for slave that supose to be expired. */
+ if (slave == exp_slave) {
+ while (rte_ring_count(slave->rx_queue) > 0) {
+ rte_ring_dequeue(slave->rx_queue, (void **)&pkt);
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+
+ retval = bond_rx(pkts, RTE_DIM(pkts));
+ if (retval > 0)
+ free_pkts(pkts, retval);
+
+ TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets",
+ retval);
+ }
+
+ /* After test only expected slave should be in EXPIRED state */
+ FOR_EACH_SLAVE(i, slave) {
+ if (slave == exp_slave)
+ TEST_ASSERT(slave->lacp_parnter_state & STATE_EXPIRED,
+ "Slave %u should be in expired.", slave->port_id);
+ else
+ TEST_ASSERT_EQUAL(bond_handshake_done(slave), 1,
+ "Slave %u should be operational.", slave->port_id);
+ }
+
+ retval = remove_slaves_and_stop_bonded_device();
+ TEST_ASSERT_SUCCESS(retval, "Test cleanup failed.");
+
+ return TEST_SUCCESS;
+}
+
+static int
+check_environment(void)
+{
+ struct slave_conf *port;
+ uint8_t i, env_state;
+ uint8_t slaves[RTE_DIM(test_params.slave_ports)];
+ int slaves_count;
+
+ env_state = 0;
+ FOR_EACH_PORT(i, port) {
+ if (rte_ring_count(port->rx_queue) != 0)
+ env_state |= 0x01;
+
+ if (rte_ring_count(port->tx_queue) != 0)
+ env_state |= 0x02;
+
+ if (port->bonded != 0)
+ env_state |= 0x04;
+
+ if (port->lacp_parnter_state != 0)
+ env_state |= 0x08;
+
+ if (env_state != 0)
+ break;
+ }
+
+ slaves_count = rte_eth_bond_slaves_get(test_params.bonded_port_id,
+ slaves, RTE_DIM(slaves));
+
+ if (slaves_count != 0)
+ env_state |= 0x10;
+
+ TEST_ASSERT_EQUAL(env_state, 0,
+ "Environment not clean (port %u):%s%s%s%s%s",
+ port->port_id,
+ env_state & 0x01 ? " slave rx queue not clean" : "",
+ env_state & 0x02 ? " slave tx queue not clean" : "",
+ env_state & 0x04 ? " port marked as enslaved" : "",
+ env_state & 0x80 ? " slave state is not reset" : "",
+ env_state & 0x10 ? " slave count not equal 0" : ".");
+
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_mode4_executor(int (*test_func)(void))
+{
+ struct slave_conf *port;
+ int test_result;
+ uint8_t i;
+ void *pkt;
+
+ /* Check if environment is clean. Fail to launch a test if there was
+ * a critical error before that prevented to reset environment. */
+ TEST_ASSERT_SUCCESS(check_environment(),
+ "Refusing to launch test in dirty environment.");
+
+ RTE_VERIFY(test_func != NULL);
+ test_result = (*test_func)();
+
+ /* If test succeed check if environment wast left in good condition. */
+ if (test_result == TEST_SUCCESS)
+ test_result = check_environment();
+
+ /* Reset environment in case test failed to do that. */
+ if (test_result != TEST_SUCCESS) {
+ TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(),
+ "Failed to stop bonded device");
+
+ FOR_EACH_PORT(i, port) {
+ while (rte_ring_count(port->rx_queue) != 0) {
+ if (rte_ring_dequeue(port->rx_queue, &pkt) == 0)
+ rte_pktmbuf_free(pkt);
+ }
+
+ while (rte_ring_count(port->tx_queue) != 0) {
+ if (rte_ring_dequeue(port->tx_queue, &pkt) == 0)
+ rte_pktmbuf_free(pkt);
+ }
+ }
+ }
+
+ return test_result;
+}
+
+static int
+test_mode4_lacp_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_lacp);
+}
+
+static int
+test_mode4_marker_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_marker);
+}
+
+static int
+test_mode4_rx_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_rx);
+}
+
+static int
+test_mode4_tx_burst_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_tx_burst);
+}
+
+static int
+test_mode4_expired_wrapper(void)
+{
+ return test_mode4_executor(&test_mode4_expired);
+}
+
+static struct unit_test_suite link_bonding_mode4_test_suite = {
+ .suite_name = "Link Bonding mode 4 Unit Test Suite",
+ .setup = test_setup,
+ .teardown = testsuite_teardown,
+ .unit_test_cases = {
+ TEST_CASE_NAMED("test_mode4_lacp", test_mode4_lacp_wrapper),
+ TEST_CASE_NAMED("test_mode4_rx", test_mode4_rx_wrapper),
+ TEST_CASE_NAMED("test_mode4_tx_burst", test_mode4_tx_burst_wrapper),
+ TEST_CASE_NAMED("test_mode4_marker", test_mode4_marker_wrapper),
+ TEST_CASE_NAMED("test_mode4_expired", test_mode4_expired_wrapper),
+ { NULL, NULL, NULL, NULL, NULL } /**< NULL terminate unit test array */
+ }
+};
+
+static int
+test_link_bonding_mode4(void)
+{
+ return unit_test_suite_runner(&link_bonding_mode4_test_suite);
+}
+
+static struct test_command link_bonding_cmd = {
+ .command = "link_bonding_mode4_autotest",
+ .callback = test_link_bonding_mode4,
+};
+
+REGISTER_TEST_COMMAND(link_bonding_cmd);
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v4 3/4] mk: Link test app against librte_pmd_ring when needed
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 1/4] test: test.h rework Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 2/4] test: Unit tests for mode 4 Tomasz Kulasek
@ 2015-02-13 10:38 ` Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 4/4] pmd_bond: Set routines required by test app global Tomasz Kulasek
2015-02-13 11:08 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Declan Doherty
4 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-02-13 10:38 UTC (permalink / raw)
To: dev
This patch links test application against librte_pmd_ring.so for shared
libraries. It's required as long as librte_pmd_ring provides some aditional
routines used for testing purposes and must be "hard-linked".
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
app/test/Makefile | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/app/test/Makefile b/app/test/Makefile
index ee0e95a..30dcdab 100644
--- a/app/test/Makefile
+++ b/app/test/Makefile
@@ -128,8 +128,12 @@ SRCS-y += test_devargs.c
SRCS-y += virtual_pmd.c
SRCS-y += packet_burst_generator.c
SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_RING),y)
SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding.c
SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding_mode4.c
+endif
+
SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring.c
SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c
@@ -147,6 +151,17 @@ CFLAGS += -D_GNU_SOURCE
# this application needs libraries first
DEPDIRS-y += lib
+# Link against shared libraries when needed
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
+ifneq ($(CONFIG_RTE_LIBRTE_PMD_RING),y)
+$(error Link bonding tests require CONFIG_RTE_LIBRTE_PMD_RING=y)
+else
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+LDLIBS += -lrte_pmd_ring
+endif
+endif
+endif
+
include $(RTE_SDK)/mk/rte.app.mk
endif
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* [dpdk-dev] [PATCH v4 4/4] pmd_bond: Set routines required by test app global
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Tomasz Kulasek
` (2 preceding siblings ...)
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 3/4] mk: Link test app against librte_pmd_ring when needed Tomasz Kulasek
@ 2015-02-13 10:38 ` Tomasz Kulasek
2015-02-13 11:08 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Declan Doherty
4 siblings, 0 replies; 30+ messages in thread
From: Tomasz Kulasek @ 2015-02-13 10:38 UTC (permalink / raw)
To: dev
rte_eth_bond_8023ad_setup and rte_eth_bond_8023ad_conf_get entries need
to be exported to be used by test application for shared libraries
compilation.
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
lib/librte_pmd_bond/rte_eth_bond_version.map | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/librte_pmd_bond/rte_eth_bond_version.map b/lib/librte_pmd_bond/rte_eth_bond_version.map
index e72e3c0..2fecbdf 100644
--- a/lib/librte_pmd_bond/rte_eth_bond_version.map
+++ b/lib/librte_pmd_bond/rte_eth_bond_version.map
@@ -15,6 +15,8 @@ DPDK_2.0 {
rte_eth_bond_slaves_get;
rte_eth_bond_xmit_policy_get;
rte_eth_bond_xmit_policy_set;
+ rte_eth_bond_8023ad_setup;
+ rte_eth_bond_8023ad_conf_get;
local: *;
};
--
1.7.9.5
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Tomasz Kulasek
` (3 preceding siblings ...)
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 4/4] pmd_bond: Set routines required by test app global Tomasz Kulasek
@ 2015-02-13 11:08 ` Declan Doherty
2015-02-18 18:00 ` Thomas Monjalon
4 siblings, 1 reply; 30+ messages in thread
From: Declan Doherty @ 2015-02-13 11:08 UTC (permalink / raw)
To: Tomasz Kulasek, dev
On 13/02/15 10:38, Tomasz Kulasek wrote:
> This patch series depends of "PMD ring" patches and should be applied after them
> to run successfully.
>
> v4 changes
> - Adapting to changes in the initialize_eth_header API
> - Fix linking problem against librte_pmd_bond.so for shared libraries
> - Patchset cleanup for smoother application
>
> v3 changes
> - Fix compilation issues for dynamic libraries
> - Re-create a series of patches to maintain consistency
>
> v2 changes
> - Patch split for better readability
>
> Tomasz Kulasek (4):
> test: test.h rework
> test: Unit tests for mode 4
> mk: Link test app against librte_pmd_ring when needed
> pmd_bond: Set routines required by test app global
>
> app/test/Makefile | 16 +
> app/test/test.h | 112 +-
> app/test/test_link_bonding.c | 2 +-
> app/test/test_link_bonding_mode4.c | 1413 ++++++++++++++++++++++++++
> lib/librte_pmd_bond/rte_eth_bond_version.map | 2 +
> 5 files changed, 1498 insertions(+), 47 deletions(-)
> create mode 100644 app/test/test_link_bonding_mode4.c
>
Series Acked-by: Declan Doherty <declan.doherty@intel.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/3] PMD ring MAC management, fix initialization, link up/down
2015-01-28 11:56 ` [dpdk-dev] [PATCH v2 0/3] PMD ring MAC management, fix initialization, link up/down Doherty, Declan
@ 2015-02-18 17:33 ` Thomas Monjalon
0 siblings, 0 replies; 30+ messages in thread
From: Thomas Monjalon @ 2015-02-18 17:33 UTC (permalink / raw)
To: Kulasek, TomaszX; +Cc: dev
> > Patch split into smaller parts to separate features from previous version.
> >
> > Tomasz Kulasek (3):
> > PMD Ring - Add link up/down functions
> > PMD Ring - Add MAC addr add/remove functions
> > PMD Ring - Fix for per device management
>
> Acked-by: Declan Doherty <declan.doherty@intel.com>
Applied, thanks
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4
2015-02-13 11:08 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Declan Doherty
@ 2015-02-18 18:00 ` Thomas Monjalon
0 siblings, 0 replies; 30+ messages in thread
From: Thomas Monjalon @ 2015-02-18 18:00 UTC (permalink / raw)
To: Tomasz Kulasek; +Cc: dev
> > This patch series depends of "PMD ring" patches and should be applied after them
> > to run successfully.
> >
> > v4 changes
> > - Adapting to changes in the initialize_eth_header API
> > - Fix linking problem against librte_pmd_bond.so for shared libraries
> > - Patchset cleanup for smoother application
> >
> > v3 changes
> > - Fix compilation issues for dynamic libraries
> > - Re-create a series of patches to maintain consistency
> >
> > v2 changes
> > - Patch split for better readability
> >
> > Tomasz Kulasek (4):
> > test: test.h rework
> > test: Unit tests for mode 4
> > mk: Link test app against librte_pmd_ring when needed
> > pmd_bond: Set routines required by test app global
>
> Series Acked-by: Declan Doherty <declan.doherty@intel.com>
Applied, thanks
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [dpdk-dev] [PATCH 1/3] bond change warning
2014-12-12 9:14 ` [dpdk-dev] [PATCH 1/3] bond change warning Michal Jastrzebski
@ 2015-02-18 18:06 ` Thomas Monjalon
0 siblings, 0 replies; 30+ messages in thread
From: Thomas Monjalon @ 2015-02-18 18:06 UTC (permalink / raw)
To: Pawel Wodkowski; +Cc: dev
> Remove function name from warning.
>
> Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Other patches of series were split in other series.
Applied, thanks
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2015-02-18 18:26 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-12 9:14 [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests Michal Jastrzebski
2014-12-12 9:14 ` [dpdk-dev] [PATCH 1/3] bond change warning Michal Jastrzebski
2015-02-18 18:06 ` Thomas Monjalon
2014-12-12 9:14 ` [dpdk-dev] [PATCH 2/3] PMD ring MAC management, fix initialization, link up/down Michal Jastrzebski
2015-01-15 10:53 ` Thomas Monjalon
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 0/3] " Tomasz Kulasek
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 1/3] PMD Ring - Add link up/down functions Tomasz Kulasek
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 2/3] PMD Ring - Add MAC addr add/remove functions Tomasz Kulasek
2015-01-19 11:56 ` [dpdk-dev] [PATCH v2 3/3] PMD Ring - Fix for MAC per device management Tomasz Kulasek
2015-01-28 11:56 ` [dpdk-dev] [PATCH v2 0/3] PMD ring MAC management, fix initialization, link up/down Doherty, Declan
2015-02-18 17:33 ` Thomas Monjalon
2014-12-12 9:14 ` [dpdk-dev] [PATCH 3/3] unit tests add mode 4 unit test Michal Jastrzebski
2015-01-15 10:55 ` Thomas Monjalon
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 0/2] " Tomasz Kulasek
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 1/2] Unit tests - test.h rework Tomasz Kulasek
2015-01-19 12:43 ` [dpdk-dev] [PATCH v2 2/2] Unit tests for mode 4 Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 0/3] " Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 1/3] test: test.h rework Tomasz Kulasek
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3 2/3] test: Unit tests for mode 4 Tomasz Kulasek
2015-02-12 11:49 ` Declan Doherty
2015-01-29 8:51 ` [dpdk-dev] [PATCH v3] mk: Link test app against librte_pmd_ring when needed Tomasz Kulasek
2015-02-12 11:50 ` Declan Doherty
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 1/4] test: test.h rework Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 2/4] test: Unit tests for mode 4 Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 3/4] mk: Link test app against librte_pmd_ring when needed Tomasz Kulasek
2015-02-13 10:38 ` [dpdk-dev] [PATCH v4 4/4] pmd_bond: Set routines required by test app global Tomasz Kulasek
2015-02-13 11:08 ` [dpdk-dev] [PATCH v4 0/4] Unit tests for mode 4 Declan Doherty
2015-02-18 18:00 ` Thomas Monjalon
2014-12-12 15:27 ` [dpdk-dev] [PATCH 0/3] bond mode 4: add unit tests Doherty, Declan
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).