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