* [dpdk-dev] [RFC 1/4] test/virtual_pmd: enable getting device operations @ 2021-06-17 8:14 Ferruh Yigit 2021-06-17 8:14 ` [dpdk-dev] [RFC 2/4] test/virtual_pmd: clean rings on close Ferruh Yigit ` (3 more replies) 0 siblings, 4 replies; 16+ messages in thread From: Ferruh Yigit @ 2021-06-17 8:14 UTC (permalink / raw) To: dev; +Cc: Ferruh Yigit This will be used to overwrite the dev_ops for various tests. Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 14 ++++++++++++-- app/test/virtual_pmd.h | 6 ++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index 7036f401ed95..4d6ce302a563 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -350,8 +350,8 @@ virtual_ethdev_rx_burst_success(void *queue __rte_unused, static uint16_t virtual_ethdev_rx_burst_fail(void *queue __rte_unused, - struct rte_mbuf **bufs __rte_unused, - uint16_t nb_pkts __rte_unused) + struct rte_mbuf **bufs __rte_unused, + uint16_t nb_pkts __rte_unused) { return 0; } @@ -614,3 +614,13 @@ virtual_ethdev_create(const char *name, struct rte_ether_addr *mac_addr, return -1; } + +struct eth_dev_ops * +virtual_ethdev_ops_get(uint16_t port_id) +{ + struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + struct virtual_ethdev_private *dev_private = dev->data->dev_private; + struct eth_dev_ops *dev_ops = &dev_private->dev_ops; + + return dev_ops; +} diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h index 120b58b27395..517dd0d2efa6 100644 --- a/app/test/virtual_pmd.h +++ b/app/test/virtual_pmd.h @@ -70,6 +70,12 @@ void virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint16_t port_id, uint8_t packet_fail_count); +/* Let application get dev_ops to be able to overwrite some operations + * per the specific test needs. + */ +struct eth_dev_ops * +virtual_ethdev_ops_get(uint16_t port_id); + #ifdef __cplusplus } #endif -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC 2/4] test/virtual_pmd: clean rings on close 2021-06-17 8:14 [dpdk-dev] [RFC 1/4] test/virtual_pmd: enable getting device operations Ferruh Yigit @ 2021-06-17 8:14 ` Ferruh Yigit 2021-06-17 8:14 ` [dpdk-dev] [RFC 3/4] test/virtual_pmd: enable updating device flags Ferruh Yigit ` (2 subsequent siblings) 3 siblings, 0 replies; 16+ messages in thread From: Ferruh Yigit @ 2021-06-17 8:14 UTC (permalink / raw) To: dev; +Cc: Ferruh Yigit Not cleaning the rings prevents creating devices again, which breaks to run some unit tests multiple times. Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index 4d6ce302a563..17f28c5a304c 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -34,7 +34,7 @@ struct virtual_ethdev_queue { }; static int -virtual_ethdev_start_success(struct rte_eth_dev *eth_dev __rte_unused) +virtual_ethdev_start_success(struct rte_eth_dev *eth_dev) { eth_dev->data->dev_started = 1; @@ -42,13 +42,13 @@ virtual_ethdev_start_success(struct rte_eth_dev *eth_dev __rte_unused) } static int -virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev __rte_unused) +virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev) { eth_dev->data->dev_started = 0; return -1; } -static int virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused) +static int virtual_ethdev_stop(struct rte_eth_dev *eth_dev) { void *pkt = NULL; struct virtual_ethdev_private *prv = eth_dev->data->dev_private; @@ -65,8 +65,13 @@ static int virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused) } static int -virtual_ethdev_close(struct rte_eth_dev *dev __rte_unused) +virtual_ethdev_close(struct rte_eth_dev *eth_dev) { + struct virtual_ethdev_private *prv = eth_dev->data->dev_private; + + rte_ring_free(prv->rx_queue); + rte_ring_free(prv->tx_queue); + return 0; } -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC 3/4] test/virtual_pmd: enable updating device flags 2021-06-17 8:14 [dpdk-dev] [RFC 1/4] test/virtual_pmd: enable getting device operations Ferruh Yigit 2021-06-17 8:14 ` [dpdk-dev] [RFC 2/4] test/virtual_pmd: clean rings on close Ferruh Yigit @ 2021-06-17 8:14 ` Ferruh Yigit 2021-06-17 8:14 ` [dpdk-dev] [RFC 4/4] test: support ethdev Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit 3 siblings, 0 replies; 16+ messages in thread From: Ferruh Yigit @ 2021-06-17 8:14 UTC (permalink / raw) To: dev; +Cc: Ferruh Yigit To be able to test various dev_flags. Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 10 ++++++++++ app/test/virtual_pmd.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index 17f28c5a304c..615243e19aed 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -629,3 +629,13 @@ virtual_ethdev_ops_get(uint16_t port_id) return dev_ops; } + +int +virtual_ethdev_set_dev_flags(uint16_t port_id, uint32_t dev_flags) +{ + struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id]; + + eth_dev->data->dev_flags = dev_flags; + + return 0; +} diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h index 517dd0d2efa6..80d5d343579a 100644 --- a/app/test/virtual_pmd.h +++ b/app/test/virtual_pmd.h @@ -76,6 +76,10 @@ virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint16_t port_id, struct eth_dev_ops * virtual_ethdev_ops_get(uint16_t port_id); +/* For application to be able to alter the device flags */ +int +virtual_ethdev_set_dev_flags(uint16_t port_id, uint32_t dev_flags); + #ifdef __cplusplus } #endif -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC 4/4] test: support ethdev 2021-06-17 8:14 [dpdk-dev] [RFC 1/4] test/virtual_pmd: enable getting device operations Ferruh Yigit 2021-06-17 8:14 ` [dpdk-dev] [RFC 2/4] test/virtual_pmd: clean rings on close Ferruh Yigit 2021-06-17 8:14 ` [dpdk-dev] [RFC 3/4] test/virtual_pmd: enable updating device flags Ferruh Yigit @ 2021-06-17 8:14 ` Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit 3 siblings, 0 replies; 16+ messages in thread From: Ferruh Yigit @ 2021-06-17 8:14 UTC (permalink / raw) To: dev, Thomas Monjalon, Andrew Rybchenko; +Cc: Ferruh Yigit Added unit test for ethdev APIs, this unit test 'ethdev_api_autotest' can run without physical device. If there are physical devices probed, they will be ignored by the unit test. A few issues fixed or some clarification added in the ehtdev library with in this unit test patch. Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- Notes: * 'rte_eth_dev_owner_unset()' error message is misleading: "Cannot set owner to port 1 already owned by ..." Unset API error message is about setting. * 'rte_eth_dev_owner_delete()' crashes, fixed here but it seems it is not used at all * 'rte_eth_dev_configure()' is too complex, there still much more things to test in that API. * Is there a way to get start/stop status of a port, should we add a new API, 'rte_eth_dev_is_started()', ? * Need a way to get bus from ethdev. Current API requires "rte_device" which is internal information from ethdev perspective. * Clarification added that PMD should implement 'dev_infos_get' for 'rte_eth_dev_configure()' support. * Tried to clarify dev_flags with more comments * In configure, for default config, having only Rx or Tx queue number pass the test but it should fail, adding more checks to 'rte_eth_dev_configure()' for it. * Do we need a way to get device 'dev_conf.rxmode.max_rx_pkt_len' value? --- app/test/meson.build | 1 + app/test/test.c | 1 + app/test/test_ethdev.c | 1160 ++++++++++++++++++++++++++++++++++ lib/ethdev/ethdev_driver.h | 6 +- lib/ethdev/rte_ethdev.c | 19 +- lib/ethdev/rte_ethdev.h | 14 +- lib/ethdev/rte_ethdev_core.h | 2 +- 7 files changed, 1197 insertions(+), 6 deletions(-) create mode 100644 app/test/test_ethdev.c diff --git a/app/test/meson.build b/app/test/meson.build index 08c82d3d23a0..c55a7ac82bd8 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -41,6 +41,7 @@ test_sources = files( 'test_efd.c', 'test_efd_perf.c', 'test_errno.c', + 'test_ethdev.c', 'test_ethdev_link.c', 'test_event_crypto_adapter.c', 'test_event_eth_rx_adapter.c', diff --git a/app/test/test.c b/app/test/test.c index 173d202e4774..82727e10b2be 100644 --- a/app/test/test.c +++ b/app/test/test.c @@ -222,6 +222,7 @@ main(int argc, char **argv) break; } cmdline_free(cl); + printf("\n"); goto out; } else { /* if no DPDK_TEST env variable, go interactive */ diff --git a/app/test/test_ethdev.c b/app/test/test_ethdev.c new file mode 100644 index 000000000000..69a2eaede1c3 --- /dev/null +++ b/app/test/test_ethdev.c @@ -0,0 +1,1160 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#include <inttypes.h> + +#include <rte_ethdev.h> +#include <ethdev_driver.h> + +#include "test.h" +#include "virtual_pmd.h" + +#define MAX_PORT_NUMBER 2 + +static uint16_t port_id[MAX_PORT_NUMBER]; +static struct eth_dev_ops *dev_ops[MAX_PORT_NUMBER]; +static uint16_t initial_port_number; +static uint16_t port_number; +static uint64_t port_owner_id; +static uint16_t invalid_port_id = 999; + +#define TEST_PMD_NAME "net_test" + +#define MAX_RX_PKTLEN 2048 + +static int +ethdev_api_setup(void) +{ + struct rte_ether_addr mac_addr = { + { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x00 }, + }; + char name[RTE_ETH_NAME_MAX_LEN]; + uint16_t local_port_id; + int ret; + + if (port_number != 0) + return TEST_SUCCESS; + + initial_port_number = rte_eth_dev_count_total(); + + snprintf(name, RTE_ETH_NAME_MAX_LEN, "%s%d", TEST_PMD_NAME, port_number); + ret = virtual_ethdev_create(name, &mac_addr, rte_socket_id(), 1); + TEST_ASSERT(ret >= 0, "Failed to create test PMD %s\n", name); + local_port_id = (uint16_t)ret; + dev_ops[port_number] = virtual_ethdev_ops_get(local_port_id); + port_id[port_number++] = local_port_id; + + snprintf(name, RTE_ETH_NAME_MAX_LEN, "%s%d", TEST_PMD_NAME, port_number); + ret = virtual_ethdev_create(name, &mac_addr, rte_socket_id(), 1); + TEST_ASSERT(ret >= 0, "Failed to create test PMD %s\n", name); + local_port_id = (uint16_t)ret; + dev_ops[port_number] = virtual_ethdev_ops_get(local_port_id); + port_id[port_number++] = local_port_id; + + return TEST_SUCCESS; +} + +static void +ethdev_api_teardown(void) +{ + int local_port_number = port_number; + char name[RTE_ETH_NAME_MAX_LEN]; + int i; + + for (i = 0; i < local_port_number; i++) { + rte_eth_dev_close(port_id[i]); + snprintf(name, RTE_ETH_NAME_MAX_LEN, "%s%d", TEST_PMD_NAME, i); + /* TODO: get bus from eth_dev */ + rte_eal_hotplug_remove("pci", name); + port_number--; + } + + /* reset global variables */ + memset(port_id, 0, MAX_PORT_NUMBER * sizeof(port_id[0])); + memset(dev_ops, 0, MAX_PORT_NUMBER * sizeof(dev_ops[0])); + port_owner_id = RTE_ETH_DEV_NO_OWNER; +} + +static int +ethdev_count_avail(void) +{ + uint16_t count; + + count = rte_eth_dev_count_avail(); + TEST_ASSERT_EQUAL(count, port_number + initial_port_number, + "Failed to get available ethdev device count\n"); + + return TEST_SUCCESS; +} + +static int +ethdev_owner_get(void) +{ + char no_name[RTE_ETH_MAX_OWNER_NAME_LEN] = ""; + struct rte_eth_dev_owner owner; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + ret = rte_eth_dev_owner_get(invalid_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, + "Owner get accepted invalid port id %u\n", + invalid_port_id); + + ret = rte_eth_dev_owner_get(port_id[i], NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Owner get accepted null owner for port id %u\n", + port_id[i]); + + ret = rte_eth_dev_owner_get(port_id[i], &owner); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to get owner for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(owner.id, RTE_ETH_DEV_NO_OWNER, + "Received owner id doesn't match with no owner id port id %u\n", + port_id[i]); + TEST_ASSERT_BUFFERS_ARE_EQUAL(owner.name, no_name, + RTE_ETH_MAX_OWNER_NAME_LEN, + "Received owner name doesn't match with no owner name port id %u\n", + port_id[i]); + } + + return TEST_SUCCESS; +} + +static int +ethdev_owner_new(void) +{ + uint64_t local_port_owner_id; + int ret; + + /* null owner id pointer */ + ret = rte_eth_dev_owner_new(NULL); + RTE_TEST_ASSERT_FAIL(ret, "NULL owner argument accepted\n"); + + ret = rte_eth_dev_owner_new(&port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get new owner id\n"); + + /* Check not same owner ID received twice */ + local_port_owner_id = port_owner_id; + ret = rte_eth_dev_owner_new(&port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get new owner id\n"); + TEST_ASSERT_NOT_EQUAL(port_owner_id, local_port_owner_id, + "Existing owner id returned\n"); + + return TEST_SUCCESS; +} + +static int +ethdev_owner_set(void) +{ + struct rte_eth_dev_owner owner = { + .id = RTE_ETH_DEV_NO_OWNER, + .name = "TEST", + }; + struct rte_eth_dev_owner owner_get; + uint16_t local_port_id = port_id[1]; + const char *alternate_name = "TEST2"; + int ret; + + /* invalid port id */ + ret = rte_eth_dev_owner_set(invalid_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Owner set accepted invalid port id %u\n", + invalid_port_id); + + /* null owner */ + ret = rte_eth_dev_owner_set(local_port_id, NULL); + RTE_TEST_ASSERT_FAIL(ret, "Owner set accepted null owner for port id %u\n", + local_port_id); + + /* no owner id */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Accepted no owner id for port id %u\n", + local_port_id); + + /* invalid owner id */ + owner.id = port_owner_id + 1; /* 'rte_eth_dev_owner_new() called twice */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Accepted invalid owner id for port id %u\n", + local_port_id); + + /* set owner */ + owner.id = port_owner_id; + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to set owner for port id %u\n", + local_port_id); + + /* get the owner back and verify */ + ret = rte_eth_dev_owner_get(local_port_id, &owner_get); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get owner for port id %u\n", + local_port_id); + TEST_ASSERT_EQUAL(owner.id, owner_get.id, + "Received owner id doesn't match with set owner id port id %u\n", + local_port_id); + TEST_ASSERT_BUFFERS_ARE_EQUAL(owner.name, owner_get.name, + RTE_ETH_MAX_OWNER_NAME_LEN, + "Received owner name doesn't match with set owner name port id %u\n", + local_port_id); + + /* set same owner */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Accepted same owner for port id %u\n", + local_port_id); + + /* no owner id after owner set */ + owner.id = RTE_ETH_DEV_NO_OWNER; + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Accepted no owner id for port id %u\n", + local_port_id); + + /* set owner with same owner id different owner name */ + owner.id = port_owner_id; + strlcpy(owner.name, alternate_name, RTE_ETH_MAX_OWNER_NAME_LEN); + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted same owner id different owner name for port id %u\n", + local_port_id); + + /* set owner with same owner name different owner id */ + owner.id = port_owner_id - 1; /* Two owner ids received */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted different owner id with same owner name for port id %u\n", + local_port_id); + + /* Set owner with very large name */ + ret = rte_eth_dev_owner_unset(local_port_id, port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to unset owner for port id %u\n", + local_port_id); + + owner.id = port_owner_id; + memset(owner.name, 'x', RTE_ETH_MAX_OWNER_NAME_LEN); + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to set owner with large name for port id %u\n", + local_port_id); + + /* Force printing the previously set large name */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted same owner with large name for port id %u\n", + local_port_id); + + return TEST_SUCCESS; +} + +/* There must be two ethdev devices created at this point, + * But one of them has owner, so available and total device counts + * should differ. + */ +static int +ethdev_count_total(void) +{ + uint16_t total_count; + uint16_t available_count; + uint16_t count; + + total_count = rte_eth_dev_count_total(); + TEST_ASSERT_EQUAL(total_count, initial_port_number + port_number, + "Failed to get total ethdev device count\n"); + + available_count = initial_port_number + port_number - 1; /* One has owner */ + count = rte_eth_dev_count_avail(); + TEST_ASSERT_EQUAL(count, available_count, + "Failed to get available ethdev device count after ownership\n"); + + return TEST_SUCCESS; +} + +static int +ethdev_owner_unset(void) +{ + char no_name[RTE_ETH_MAX_OWNER_NAME_LEN] = ""; + uint16_t local_port_id = port_id[1]; + struct rte_eth_dev_owner owner; + uint64_t invalid_owner_id; + int ret; + + /* unset owner with invalid port id */ + ret = rte_eth_dev_owner_unset(invalid_port_id, port_owner_id); + RTE_TEST_ASSERT_FAIL(ret, "Owner unset accepted invalid port id %u\n", + invalid_port_id); + + /* unset owner with invalid owner id */ + invalid_owner_id = port_owner_id - 1; + ret = rte_eth_dev_owner_unset(local_port_id, invalid_owner_id); + RTE_TEST_ASSERT_FAIL(ret, + "Owner unset accepted invalid owner id %" PRIu64 " for port id %u\n", + invalid_owner_id, local_port_id); + + invalid_owner_id = port_owner_id + 1; + ret = rte_eth_dev_owner_unset(local_port_id, invalid_owner_id); + RTE_TEST_ASSERT_FAIL(ret, + "Owner unset accepted invalid owner id %" PRIu64 " for port id %u\n", + invalid_owner_id, local_port_id); + + /* unset owner */ + ret = rte_eth_dev_owner_unset(local_port_id, port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to unset owner for port id %u\n", + local_port_id); + + /* verify owner unset */ + ret = rte_eth_dev_owner_get(local_port_id, &owner); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get owner for port id %u\n", + local_port_id); + TEST_ASSERT_EQUAL(owner.id, RTE_ETH_DEV_NO_OWNER, + "Received owner id doesn't match with no owner id port id %u\n", + local_port_id); + TEST_ASSERT_BUFFERS_ARE_EQUAL(owner.name, no_name, + RTE_ETH_MAX_OWNER_NAME_LEN, + "Received owner name doesn't match with no owner name port id %u\n", + local_port_id); + + return TEST_SUCCESS; +} + +static int +ethdev_owner_delete(void) +{ + struct rte_eth_dev_owner owner = { + .id = port_owner_id, + .name = "TEST", + }; + uint64_t invalid_owner_id; + int count; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + /* set owner */ + ret = rte_eth_dev_owner_set(port_id[i], &owner); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to set owner for port id %u\n", + port_id[i]); + + /* delete owner with invalid owner id */ + invalid_owner_id = port_owner_id - 1; + ret = rte_eth_dev_owner_unset(port_id[i], invalid_owner_id); + RTE_TEST_ASSERT_FAIL(ret, + "Owner delete accepted invalid owner id %" PRIu64 " for port id %u\n", + invalid_owner_id, port_id[i]); + + invalid_owner_id = port_owner_id + 1; + ret = rte_eth_dev_owner_unset(port_id[i], invalid_owner_id); + RTE_TEST_ASSERT_FAIL(ret, + "Owner delete accepted invalid owner id %" PRIu64 " for port id %u\n", + invalid_owner_id, port_id[i]); + } + + ret = rte_eth_dev_owner_delete(port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to delete owner id %" PRIu64 "\n", + port_owner_id); + + count = rte_eth_dev_count_avail(); + TEST_ASSERT_EQUAL(count, initial_port_number + port_number, + "Failed to delete owner id %" PRIu64 " from some ethdev devices\n", + port_owner_id); + + return TEST_SUCCESS; +} + +static int +configure_fail(struct rte_eth_dev *dev __rte_unused) +{ + return -1; +} + +static int +info_get_default_config(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ +#define DEFAULT_BURST_SIZE 99 +#define DEFAULT_RING_SIZE 129 +#define DEFAULT_QUEUE_NUMBER 333 + struct rte_eth_dev_portconf portconfig = { + .burst_size = DEFAULT_BURST_SIZE, + .ring_size = DEFAULT_BURST_SIZE, + .nb_queues = DEFAULT_QUEUE_NUMBER, + }; + dev_info->default_rxportconf = portconfig; + dev_info->default_txportconf = portconfig; + + dev_info->max_rx_queues = DEFAULT_QUEUE_NUMBER + 1; + dev_info->max_tx_queues = DEFAULT_QUEUE_NUMBER + 1; + + return 0; +} + +static int +info_get_offload_jumbo(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_pktlen = MAX_RX_PKTLEN; + + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_JUMBO_FRAME; + + return 0; +} + +static int +info_get_min_max_mtu(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_pktlen = MAX_RX_PKTLEN; + + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_JUMBO_FRAME; + + dev_info->min_mtu = RTE_ETHER_MIN_MTU; + dev_info->max_mtu = MAX_RX_PKTLEN - 100; + + return 0; +} + +static int +info_get_lro(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_TCP_LRO; + + return 0; +} + +static int +info_get_lro_pkt_size(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ +#define MAX_LRO_PKTLEN (MAX_RX_PKTLEN * 2) + dev_info->max_lro_pkt_size = MAX_LRO_PKTLEN; + + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_TCP_LRO; + + return 0; +} + +static int +info_get_rss_hash_offload(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_RSS_HASH; + + return 0; +} + +static int +ethdev_configure(void) +{ + struct eth_dev_ops *local_dev_ops; + struct eth_dev_ops backup_dev_ops; + struct rte_eth_dev_info dev_info; + struct rte_eth_conf dev_conf; + uint16_t nb_rx_q = 0; + uint16_t nb_tx_q = 0; + int ret; + int i; + + memset(&dev_conf, 0, sizeof(dev_conf)); + + for (i = 0; i < port_number; i++) { + /* invalid port id */ + ret = rte_eth_dev_configure(invalid_port_id, nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Configure accepted invalid port id %u\n", + invalid_port_id); + + /* set NULL config */ + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL configuration for port id %u\n", + port_id[i]); + + /* no configure dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_configure = NULL; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL configuration for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* no infos_get dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = NULL; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL info get dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* failing dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_configure = configure_fail; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted failing device configuration for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* configure after start */ + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start port id %u\n", + port_id[i]); + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Configuring an already started port id %u\n", + port_id[i]); + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop port id %u\n", + port_id[i]); + + /* get device info for various tests below */ + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + + /* set big Rx queue number */ + nb_rx_q = RTE_MAX_QUEUES_PER_PORT + 1; + nb_tx_q = 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue number > RTE_MAX_QUEUES configuration for port id %u\n", + port_id[i]); + + nb_rx_q = dev_info.max_rx_queues + 1; + nb_tx_q = 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue number > max_rx_queues configuration for port id %u\n", + port_id[i]); + + /* set big Tx queue number */ + nb_rx_q = 1; + nb_tx_q = RTE_MAX_QUEUES_PER_PORT + 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Tx queue number > RTE_MAX_QUEUES configuration for port id %u\n", + port_id[i]); + + nb_rx_q = 1; + nb_tx_q = dev_info.max_tx_queues + 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Tx queue number > max_tx_queues configuration for port id %u\n", + port_id[i]); + nb_rx_q = 1; + nb_tx_q = 1; + + /* request default queue number only for Rx or Tx */ + nb_rx_q = 1; + nb_tx_q = 0; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted only Tx default queue number for port id %u\n", + port_id[i]); + + nb_rx_q = 0; + nb_tx_q = 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted only Rx default queue number for port id %u\n", + port_id[i]); + nb_rx_q = 1; + nb_tx_q = 1; + + /* request not supported LSC */ + dev_conf.intr_conf.lsc = 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted LSC interrupt config port id %u\n", + port_id[i]); + dev_conf.intr_conf.lsc = 0; + + /* request not supported RMV */ + dev_conf.intr_conf.rmv = 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted LSC interrupt config port id %u\n", + port_id[i]); + dev_conf.intr_conf.rmv = 0; + + /* configure device */ + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + + /* requested supported device features */ + virtual_ethdev_set_dev_flags(port_id[i], + RTE_ETH_DEV_INTR_LSC | RTE_ETH_DEV_INTR_RMV); + dev_conf.intr_conf.lsc = 1; + dev_conf.intr_conf.rmv = 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to configure with device flags for port id %u\n", + port_id[i]); + dev_conf.intr_conf.lsc = 0; + dev_conf.intr_conf.rmv = 0; + + /* Use default Rx/Tx queue numbers */ + nb_rx_q = 0; + nb_tx_q = 0; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.nb_rx_queues, + RTE_ETH_DEV_FALLBACK_RX_NBQUEUES, + "Default Rx queue number is wrong for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.nb_tx_queues, + RTE_ETH_DEV_FALLBACK_TX_NBQUEUES, + "Default Tx queue number is wrong for port id %u\n", + port_id[i]); + + /* Use PMD provided Rx/Tx queue numbers */ + nb_rx_q = 0; + nb_tx_q = 0; + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_default_config; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.nb_rx_queues, DEFAULT_QUEUE_NUMBER, + "Default driver Rx queue number is wrong for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.nb_tx_queues, DEFAULT_QUEUE_NUMBER, + "Default driver Tx queue number is wrong for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + nb_rx_q = 1; + nb_tx_q = 1; + + /* check max_rx_pkt_len without jumbo frame support */ + uint16_t overhead_len; + struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id[i]]; + overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; + dev_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MTU + overhead_len + 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + TEST_ASSERT_NOT_EQUAL(eth_dev->data->dev_conf.rxmode.max_rx_pkt_len, + dev_conf.rxmode.max_rx_pkt_len, + "Accepted Rx packet length bigger than max MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(eth_dev->data->dev_conf.rxmode.max_rx_pkt_len, + (uint32_t)(RTE_ETHER_MTU + overhead_len), + "Max Rx packet length calculated wrong for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + + dev_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MIN_MTU + overhead_len - 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + TEST_ASSERT_NOT_EQUAL(eth_dev->data->dev_conf.rxmode.max_rx_pkt_len, + dev_conf.rxmode.max_rx_pkt_len, + "Accepted Rx packet length less than min MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(eth_dev->data->dev_conf.rxmode.max_rx_pkt_len, + (uint32_t)(RTE_ETHER_MTU + overhead_len), + "Max Rx packet length calculated wrong for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + + /* check max_rx_pkt_len with jumbo frame support */ + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN + 1; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted Rx packet length bigger than supported by device for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + + dev_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MIN_LEN - 1; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted Rx packet length less than min MTU for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + + uint16_t mtu; + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_offload_jumbo; + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_get_mtu(port_id[i], &mtu); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_conf.rxmode.max_rx_pkt_len - overhead_len, + mtu, + "MTU calculated wrong on configure for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + *local_dev_ops = backup_dev_ops; + + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_offload_jumbo; + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_get_mtu(port_id[i], &mtu); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_conf.rxmode.max_rx_pkt_len - overhead_len, + mtu, + "MTU calculated wrong on configure for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + *local_dev_ops = backup_dev_ops; + + /* max_rx_pkt_len with jumbo frame with min/max MTU */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_min_max_mtu; + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + overhead_len = dev_info.max_rx_pktlen - dev_info.max_mtu; + ret = rte_eth_dev_get_mtu(port_id[i], &mtu); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_conf.rxmode.max_rx_pkt_len - overhead_len, + mtu, + "MTU calculated wrong on configure for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + *local_dev_ops = backup_dev_ops; + + /* LRO */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_lro; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_TCP_LRO; + dev_conf.rxmode.max_lro_pkt_size = MAX_RX_PKTLEN * 2; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted different LRO packet size when driver limit is missing for port id %u\n", + port_id[i]); + dev_conf.rxmode.offloads = 0; + dev_conf.rxmode.max_lro_pkt_size = 0; + *local_dev_ops = backup_dev_ops; + + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_lro_pkt_size; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_TCP_LRO; + dev_conf.rxmode.max_lro_pkt_size = MAX_LRO_PKTLEN + 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted LRO packet size bigger than what device supports for port id %u\n", + port_id[i]); + dev_conf.rxmode.offloads = 0; + dev_conf.rxmode.max_lro_pkt_size = 0; + *local_dev_ops = backup_dev_ops; + + /* offloads */ + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted offload that is not in the capability for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + + /* RSS hash function */ + dev_conf.rx_adv_conf.rss_conf.rss_hf = ETH_RSS_ETH; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted RSS hash function that is not in the capability for port id %u\n", + port_id[i]); + dev_conf.rx_adv_conf.rss_conf.rss_hf = 0; + + /* RSS hash offload */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_rss_hash_offload; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_RSS_HASH; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted RSS hash offload without RSS for port id %u\n", + port_id[i]); + dev_conf.rxmode.offloads = 0; + *local_dev_ops = backup_dev_ops; + + } + + // rss_hf src_only and dst_only + // eth_dev_tx_queue_config + // eth_dev_rx_queue_config + // RTE_ETHDEV_PROFILE_WITH_VTUNE + // eth_dev_validate_offloads + // restore config + // restore mtu + + return TEST_SUCCESS; +} + + +static const char *virtual_ethdev_driver_name = "Virtual PMD"; +static int +info_get_success(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 = MAX_RX_PKTLEN; + + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->min_rx_bufsize = 0; + + return 0; +} + +static int +info_get_fail(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info __rte_unused) +{ + return -1; +} + +static int +info_get_max_queues(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_queues = RTE_MAX_QUEUES_PER_PORT + 1; + dev_info->max_tx_queues = RTE_MAX_QUEUES_PER_PORT + 1; + + return 0; +} + +static int +info_get_mtu(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ +#define MIN_MTU 256 +#define MAX_MTU 512 + dev_info->min_mtu = MIN_MTU; + dev_info->max_mtu = MAX_MTU; + + return 0; +} + +static int +ethdev_info_get(void) +{ + struct eth_dev_ops *local_dev_ops; + struct eth_dev_ops backup_dev_ops; + struct rte_eth_dev_info dev_info; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + /* invalid port id */ + ret = rte_eth_dev_info_get(invalid_port_id, &dev_info); + RTE_TEST_ASSERT_FAIL(ret, + "Getting info accepted invalid port id %u\n", + invalid_port_id); + + /* NULL info */ + ret = rte_eth_dev_info_get(port_id[i], NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL info struct for port id %u\n", + port_id[i]); + + /* no infos_get dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = NULL; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL info get dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* failing dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_fail; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted failing device info get for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* get info */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_success; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* big max queues number */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_max_queues; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_NOT_EQUAL(dev_info.nb_rx_queues, RTE_MAX_QUEUES_PER_PORT + 1, + "Accepted big Rx queue number for port id %u\n", + port_id[i]); + TEST_ASSERT_NOT_EQUAL(dev_info.nb_tx_queues, RTE_MAX_QUEUES_PER_PORT + 1, + "Accepted big Tx queue number for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* min/max MTU */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_mtu; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.min_mtu, MIN_MTU, + "Received min MTU is wrong for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.max_mtu, MAX_MTU, + "Received max MTU is wrong for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* verify dev_flags */ +#define DEV_FLAG 0xABCD + uint32_t local_dev_flag = DEV_FLAG; + virtual_ethdev_set_dev_flags(port_id[i], local_dev_flag); + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(*dev_info.dev_flags, local_dev_flag, + "Received device flags is wrong for port id %u\n", + port_id[i]); + } + + return TEST_SUCCESS; +} + +static int +ethdev_rx_queue_setup(void) +{ + return TEST_SUCCESS; +} + +static int +ethdev_tx_queue_setup(void) +{ + return TEST_SUCCESS; +} + +static int +start_fail(struct rte_eth_dev *dev __rte_unused) +{ + return -1; +} + +static int +ethdev_start(void) +{ + struct eth_dev_ops *local_dev_ops; + struct eth_dev_ops backup_dev_ops; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + /* invalid port id */ + ret = rte_eth_dev_start(invalid_port_id); + RTE_TEST_ASSERT_FAIL(ret, "Start accepted invalid port id %u\n", + invalid_port_id); + + /* no dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_start = NULL; + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL start dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* failing dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_start = start_fail; + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted failing device start for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start port id %u\n", + port_id[i]); + + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to start already started port id %u\n", + port_id[i]); + } + + return TEST_SUCCESS; +} + +static int +stop_fail(struct rte_eth_dev *dev __rte_unused) +{ + return -1; +} + +static int +ethdev_stop(void) +{ + struct eth_dev_ops *local_dev_ops; + struct eth_dev_ops backup_dev_ops; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + /* invalid port id */ + ret = rte_eth_dev_stop(invalid_port_id); + RTE_TEST_ASSERT_FAIL(ret, "Stop accepted invalid port id %u\n", + invalid_port_id); + + /* no dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_stop = NULL; + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL stop dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* failing dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_stop = stop_fail; + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted failing device stop for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop port id %u\n", + port_id[i]); + + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to stop already stopped port id %u\n", + port_id[i]); + } + + return TEST_SUCCESS; +} + +static struct unit_test_suite ethdev_api_testsuite = { + .suite_name = "ethdev API unit test suite", + .setup = ethdev_api_setup, + .teardown = ethdev_api_teardown, + .unit_test_cases = { + TEST_CASE(ethdev_count_avail), + TEST_CASE(ethdev_owner_get), + TEST_CASE(ethdev_owner_new), + TEST_CASE(ethdev_owner_set), + TEST_CASE(ethdev_count_total), + TEST_CASE(ethdev_owner_unset), + TEST_CASE(ethdev_owner_delete), + TEST_CASE(ethdev_configure), + TEST_CASE(ethdev_info_get), + TEST_CASE(ethdev_rx_queue_setup), + TEST_CASE(ethdev_tx_queue_setup), + TEST_CASE(ethdev_start), + TEST_CASE(ethdev_stop), + TEST_CASES_END(), + }, +}; + +static int +test_ethdev_api(void) +{ + return unit_test_suite_runner(ðdev_api_testsuite); +} + +REGISTER_TEST_COMMAND(ethdev_api_autotest, test_ethdev_api); diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h index 170a4e22a7c1..26e247f160d4 100644 --- a/lib/ethdev/ethdev_driver.h +++ b/lib/ethdev/ethdev_driver.h @@ -31,7 +31,11 @@ struct rte_hairpin_peer_info; */ typedef int (*eth_dev_configure_t)(struct rte_eth_dev *dev); -/**< @internal Ethernet device configuration. */ +/**< @internal Ethernet device configuration. + * + * For ``rte_eth_dev_configure()`` API both ``eth_dev_configure_t`` and + * ``eth_dev_infos_get_t`` needs to be implemented by PMD. + * */ typedef int (*eth_dev_start_t)(struct rte_eth_dev *dev); /**< @internal Function used to start a configured Ethernet device. */ diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c index c607eabb5b0c..8e6e632dec9c 100644 --- a/lib/ethdev/rte_ethdev.c +++ b/lib/ethdev/rte_ethdev.c @@ -694,6 +694,7 @@ eth_dev_owner_set(const uint16_t port_id, const uint64_t old_owner_id, } /* can not truncate (same structure) */ + memset(port_owner->name, 0, RTE_ETH_MAX_OWNER_NAME_LEN); strlcpy(port_owner->name, new_owner->name, RTE_ETH_MAX_OWNER_NAME_LEN); port_owner->id = new_owner->id; @@ -748,10 +749,13 @@ rte_eth_dev_owner_delete(const uint64_t owner_id) rte_spinlock_lock(ð_dev_shared_data->ownership_lock); if (eth_is_valid_owner_id(owner_id)) { - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (rte_eth_devices[port_id].data->owner.id == owner_id) - memset(&rte_eth_devices[port_id].data->owner, 0, + for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { + struct rte_eth_dev_data *data = + rte_eth_devices[port_id].data; + if (data != NULL && data->owner.id == owner_id) + memset(&data->owner, 0, sizeof(struct rte_eth_dev_owner)); + } RTE_ETHDEV_LOG(NOTICE, "All port owners owned by %016"PRIx64" identifier have removed\n", owner_id); @@ -1387,6 +1391,15 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q, * If driver does not provide any preferred valued, fall back on * EAL defaults. */ + if ((nb_rx_q & nb_tx_q) == 0 && (nb_rx_q | nb_tx_q) != 0) { + RTE_ETHDEV_LOG(ERR, + "Ethdev port_id (%u), Rx queue number (%u) and Tx queue number (%u) " + "should be both zero or both non-zero\n", + port_id, nb_rx_q, nb_tx_q); + ret = -EINVAL; + goto rollback; + } + if (nb_rx_q == 0 && nb_tx_q == 0) { nb_rx_q = dev_info.default_rxportconf.nb_queues; if (nb_rx_q == 0) diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index faf3bd901d75..a6ab64abf1df 100644 --- a/lib/ethdev/rte_ethdev.h +++ b/lib/ethdev/rte_ethdev.h @@ -1837,6 +1837,10 @@ struct rte_eth_dev_owner { char name[RTE_ETH_MAX_OWNER_NAME_LEN]; /**< The owner name. */ }; +/** + * Device flags set on ``eth_dev->data->dev_flags`` by drivers. + * These values can be received via ``rte_eth_dev_info_get()`` + */ /** PMD supports thread-safe flow operations */ #define RTE_ETH_DEV_FLOW_OPS_THREAD_SAFE 0x0001 /** Device supports link state interrupt */ @@ -1980,6 +1984,10 @@ int rte_eth_dev_owner_new(uint64_t *owner_id); * * Set an Ethernet device owner. * + * Once an owner is set for an Ethernet device, setting owner again will fail, + * even it is exact same owner. + * Owner ids not obtained by ``rte_eth_dev_owner_new()`` are rejected. + * * @param port_id * The identifier of the port to own. * @param owner @@ -2524,6 +2532,8 @@ int rte_eth_dev_tx_queue_stop(uint16_t port_id, uint16_t tx_queue_id); * On success, all basic functions exported by the Ethernet API (link status, * receive/transmit, and so on) can be invoked. * + * Starting an already started port returns success. + * * @param port_id * The port identifier of the Ethernet device. * @return @@ -2536,6 +2546,8 @@ int rte_eth_dev_start(uint16_t port_id); * Stop an Ethernet device. The device can be restarted with a call to * rte_eth_dev_start() * + * Stopping an already stopped port returns success. + * * @param port_id * The port identifier of the Ethernet device. * @return @@ -3036,7 +3048,7 @@ int rte_eth_macaddr_get(uint16_t port_id, struct rte_ether_addr *mac_addr); * min_mtu = RTE_ETHER_MIN_MTU * max_mtu = UINT16_MAX * - * The following fields will be populated if support for dev_infos_get() + *ops The following fields will be populated if support for dev_infos_get() * exists for the device and the rte_eth_dev 'dev' has been populated * successfully with a call to it: * diff --git a/lib/ethdev/rte_ethdev_core.h b/lib/ethdev/rte_ethdev_core.h index 4679d948fa5e..43ab76760691 100644 --- a/lib/ethdev/rte_ethdev_core.h +++ b/lib/ethdev/rte_ethdev_core.h @@ -172,7 +172,7 @@ struct rte_eth_dev_data { /**< Queues state: HAIRPIN(2) / STARTED(1) / STOPPED(0). */ uint8_t tx_queue_state[RTE_MAX_QUEUES_PER_PORT]; /**< Queues state: HAIRPIN(2) / STARTED(1) / STOPPED(0). */ - uint32_t dev_flags; /**< Capabilities. */ + uint32_t dev_flags; /**< Device flags */ int numa_node; /**< NUMA node connection. */ struct rte_vlan_filter_conf vlan_filter_conf; /**< VLAN filter configuration. */ -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close 2021-06-17 8:14 [dpdk-dev] [RFC 1/4] test/virtual_pmd: enable getting device operations Ferruh Yigit ` (2 preceding siblings ...) 2021-06-17 8:14 ` [dpdk-dev] [RFC 4/4] test: support ethdev Ferruh Yigit @ 2021-07-16 14:27 ` Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 2/8] test/virtual_pmd: enable getting device operations Ferruh Yigit ` (7 more replies) 3 siblings, 8 replies; 16+ messages in thread From: Ferruh Yigit @ 2021-07-16 14:27 UTC (permalink / raw) To: Andrew Rybchenko, Thomas Monjalon; +Cc: Ferruh Yigit, dev Not cleaning the rings prevents creating devices again, which breaks to run some unit tests multiple times. Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index 7036f401ed95..6098e633f35a 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -34,7 +34,7 @@ struct virtual_ethdev_queue { }; static int -virtual_ethdev_start_success(struct rte_eth_dev *eth_dev __rte_unused) +virtual_ethdev_start_success(struct rte_eth_dev *eth_dev) { eth_dev->data->dev_started = 1; @@ -42,13 +42,13 @@ virtual_ethdev_start_success(struct rte_eth_dev *eth_dev __rte_unused) } static int -virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev __rte_unused) +virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev) { eth_dev->data->dev_started = 0; return -1; } -static int virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused) +static int virtual_ethdev_stop(struct rte_eth_dev *eth_dev) { void *pkt = NULL; struct virtual_ethdev_private *prv = eth_dev->data->dev_private; @@ -65,8 +65,13 @@ static int virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused) } static int -virtual_ethdev_close(struct rte_eth_dev *dev __rte_unused) +virtual_ethdev_close(struct rte_eth_dev *eth_dev) { + struct virtual_ethdev_private *prv = eth_dev->data->dev_private; + + rte_ring_free(prv->rx_queue); + rte_ring_free(prv->tx_queue); + return 0; } -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC v2 2/8] test/virtual_pmd: enable getting device operations 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit @ 2021-07-16 14:27 ` Ferruh Yigit 2023-08-22 21:10 ` Stephen Hemminger 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 3/8] test/virtual_pmd: enable updating device flags Ferruh Yigit ` (6 subsequent siblings) 7 siblings, 1 reply; 16+ messages in thread From: Ferruh Yigit @ 2021-07-16 14:27 UTC (permalink / raw) To: Andrew Rybchenko, Thomas Monjalon; +Cc: Ferruh Yigit, dev This will be used to overwrite the dev_ops for various tests. Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 14 ++++++++++++-- app/test/virtual_pmd.h | 6 ++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index 6098e633f35a..17f28c5a304c 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -355,8 +355,8 @@ virtual_ethdev_rx_burst_success(void *queue __rte_unused, static uint16_t virtual_ethdev_rx_burst_fail(void *queue __rte_unused, - struct rte_mbuf **bufs __rte_unused, - uint16_t nb_pkts __rte_unused) + struct rte_mbuf **bufs __rte_unused, + uint16_t nb_pkts __rte_unused) { return 0; } @@ -619,3 +619,13 @@ virtual_ethdev_create(const char *name, struct rte_ether_addr *mac_addr, return -1; } + +struct eth_dev_ops * +virtual_ethdev_ops_get(uint16_t port_id) +{ + struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + struct virtual_ethdev_private *dev_private = dev->data->dev_private; + struct eth_dev_ops *dev_ops = &dev_private->dev_ops; + + return dev_ops; +} diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h index 120b58b27395..517dd0d2efa6 100644 --- a/app/test/virtual_pmd.h +++ b/app/test/virtual_pmd.h @@ -70,6 +70,12 @@ void virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint16_t port_id, uint8_t packet_fail_count); +/* Let application get dev_ops to be able to overwrite some operations + * per the specific test needs. + */ +struct eth_dev_ops * +virtual_ethdev_ops_get(uint16_t port_id); + #ifdef __cplusplus } #endif -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [dpdk-dev] [RFC v2 2/8] test/virtual_pmd: enable getting device operations 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 2/8] test/virtual_pmd: enable getting device operations Ferruh Yigit @ 2023-08-22 21:10 ` Stephen Hemminger 0 siblings, 0 replies; 16+ messages in thread From: Stephen Hemminger @ 2023-08-22 21:10 UTC (permalink / raw) To: Ferruh Yigit; +Cc: Andrew Rybchenko, Thomas Monjalon, dev Looking at this old patch. On Fri, 16 Jul 2021 15:27:54 +0100 Ferruh Yigit <ferruh.yigit@intel.com> wrote: > diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c > index 6098e633f35a..17f28c5a304c 100644 > --- a/app/test/virtual_pmd.c > +++ b/app/test/virtual_pmd.c > @@ -355,8 +355,8 @@ virtual_ethdev_rx_burst_success(void *queue __rte_unused, > > static uint16_t > virtual_ethdev_rx_burst_fail(void *queue __rte_unused, > - struct rte_mbuf **bufs __rte_unused, > - uint16_t nb_pkts __rte_unused) > + struct rte_mbuf **bufs __rte_unused, > + uint16_t nb_pkts __rte_unused) No need for just reindenting if code didn't change here. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC v2 3/8] test/virtual_pmd: enable updating device flags 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 2/8] test/virtual_pmd: enable getting device operations Ferruh Yigit @ 2021-07-16 14:27 ` Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 4/8] test/virtual_pmd: enable getting device data Ferruh Yigit ` (5 subsequent siblings) 7 siblings, 0 replies; 16+ messages in thread From: Ferruh Yigit @ 2021-07-16 14:27 UTC (permalink / raw) To: Andrew Rybchenko, Thomas Monjalon; +Cc: Ferruh Yigit, dev To be able to test various dev_flags. Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 10 ++++++++++ app/test/virtual_pmd.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index 17f28c5a304c..615243e19aed 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -629,3 +629,13 @@ virtual_ethdev_ops_get(uint16_t port_id) return dev_ops; } + +int +virtual_ethdev_set_dev_flags(uint16_t port_id, uint32_t dev_flags) +{ + struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id]; + + eth_dev->data->dev_flags = dev_flags; + + return 0; +} diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h index 517dd0d2efa6..80d5d343579a 100644 --- a/app/test/virtual_pmd.h +++ b/app/test/virtual_pmd.h @@ -76,6 +76,10 @@ virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint16_t port_id, struct eth_dev_ops * virtual_ethdev_ops_get(uint16_t port_id); +/* For application to be able to alter the device flags */ +int +virtual_ethdev_set_dev_flags(uint16_t port_id, uint32_t dev_flags); + #ifdef __cplusplus } #endif -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC v2 4/8] test/virtual_pmd: enable getting device data 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 2/8] test/virtual_pmd: enable getting device operations Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 3/8] test/virtual_pmd: enable updating device flags Ferruh Yigit @ 2021-07-16 14:27 ` Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 5/8] test/virtual_pmd: support get queue info device ops Ferruh Yigit ` (4 subsequent siblings) 7 siblings, 0 replies; 16+ messages in thread From: Ferruh Yigit @ 2021-07-16 14:27 UTC (permalink / raw) To: Andrew Rybchenko, Thomas Monjalon; +Cc: Ferruh Yigit, dev Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 10 ++++++++++ app/test/virtual_pmd.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index 615243e19aed..f2d807de8d89 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -639,3 +639,13 @@ virtual_ethdev_set_dev_flags(uint16_t port_id, uint32_t dev_flags) return 0; } + +int +virtual_ethdev_get_dev_data(uint16_t port_id, struct rte_eth_dev_data **data) +{ + struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id]; + + *data = eth_dev->data; + + return 0; +} diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h index 80d5d343579a..374bb4148f96 100644 --- a/app/test/virtual_pmd.h +++ b/app/test/virtual_pmd.h @@ -80,6 +80,10 @@ virtual_ethdev_ops_get(uint16_t port_id); int virtual_ethdev_set_dev_flags(uint16_t port_id, uint32_t dev_flags); +/* Get device data for various checks */ +int +virtual_ethdev_get_dev_data(uint16_t port_id, struct rte_eth_dev_data **data); + #ifdef __cplusplus } #endif -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC v2 5/8] test/virtual_pmd: support get queue info device ops 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit ` (2 preceding siblings ...) 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 4/8] test/virtual_pmd: enable getting device data Ferruh Yigit @ 2021-07-16 14:27 ` Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 6/8] test/virtual_pmd: provide descriptor limit info Ferruh Yigit ` (3 subsequent siblings) 7 siblings, 0 replies; 16+ messages in thread From: Ferruh Yigit @ 2021-07-16 14:27 UTC (permalink / raw) To: Andrew Rybchenko, Thomas Monjalon; +Cc: Ferruh Yigit, dev Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index f2d807de8d89..e0ea213ae231 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -31,6 +31,8 @@ struct virtual_ethdev_private { struct virtual_ethdev_queue { int port_id; int queue_id; + uint16_t nb_desc; + struct rte_eth_rxconf rx_conf; }; static int @@ -106,9 +108,9 @@ virtual_ethdev_info_get(struct rte_eth_dev *dev __rte_unused, 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, + uint16_t rx_queue_id, uint16_t nb_rx_desc, unsigned int socket_id, - const struct rte_eth_rxconf *rx_conf __rte_unused, + const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool __rte_unused) { struct virtual_ethdev_queue *rx_q; @@ -121,6 +123,8 @@ virtual_ethdev_rx_queue_setup_success(struct rte_eth_dev *dev, rx_q->port_id = dev->data->port_id; rx_q->queue_id = rx_queue_id; + rx_q->nb_desc = nb_rx_desc; + rx_q->rx_conf = *rx_conf; dev->data->rx_queues[rx_queue_id] = rx_q; @@ -159,6 +163,23 @@ virtual_ethdev_tx_queue_setup_success(struct rte_eth_dev *dev, return 0; } +static void +virtual_ethdev_rx_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id, + struct rte_eth_rxq_info *qinfo) +{ + struct virtual_ethdev_queue *rx_q = dev->data->rx_queues[rx_queue_id]; + + qinfo->nb_desc = rx_q->nb_desc; + qinfo->conf = rx_q->rx_conf; +} + +static void +virtual_ethdev_tx_info_get(struct rte_eth_dev *dev __rte_unused, + uint16_t tx_queue_id __rte_unused, + struct rte_eth_txq_info *qinfo __rte_unused) +{ +} + 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, @@ -248,6 +269,8 @@ static const struct eth_dev_ops virtual_ethdev_default_dev_ops = { .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, + .rxq_info_get = virtual_ethdev_rx_info_get, + .txq_info_get = virtual_ethdev_tx_info_get, .rx_queue_release = virtual_ethdev_rx_queue_release, .tx_queue_release = virtual_ethdev_tx_queue_release, .link_update = virtual_ethdev_link_update_success, -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC v2 6/8] test/virtual_pmd: provide descriptor limit info 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit ` (3 preceding siblings ...) 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 5/8] test/virtual_pmd: support get queue info device ops Ferruh Yigit @ 2021-07-16 14:27 ` Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 7/8] test/virtual_pmd: support queue start/stop Ferruh Yigit ` (2 subsequent siblings) 7 siblings, 0 replies; 16+ messages in thread From: Ferruh Yigit @ 2021-07-16 14:27 UTC (permalink / raw) To: Andrew Rybchenko, Thomas Monjalon; +Cc: Ferruh Yigit, dev Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 4 ++++ app/test/virtual_pmd.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index e0ea213ae231..27c8501b96a7 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -103,6 +103,10 @@ virtual_ethdev_info_get(struct rte_eth_dev *dev __rte_unused, dev_info->min_rx_bufsize = 0; + dev_info->rx_desc_lim.nb_max = VIRTUAL_ETHDEV_MAX_DESC_NUM; + dev_info->rx_desc_lim.nb_min = VIRTUAL_ETHDEV_MIN_DESC_NUM; + dev_info->rx_desc_lim.nb_align = VIRTUAL_ETHDEV_DESC_ALIGN; + return 0; } diff --git a/app/test/virtual_pmd.h b/app/test/virtual_pmd.h index 374bb4148f96..7e11d23f598e 100644 --- a/app/test/virtual_pmd.h +++ b/app/test/virtual_pmd.h @@ -11,6 +11,10 @@ extern "C" { #include <rte_ether.h> +#define VIRTUAL_ETHDEV_MAX_DESC_NUM 2048 +#define VIRTUAL_ETHDEV_MIN_DESC_NUM 32 +#define VIRTUAL_ETHDEV_DESC_ALIGN 8 + int virtual_ethdev_init(void); -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC v2 7/8] test/virtual_pmd: support queue start/stop 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit ` (4 preceding siblings ...) 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 6/8] test/virtual_pmd: provide descriptor limit info Ferruh Yigit @ 2021-07-16 14:27 ` Ferruh Yigit 2023-08-22 21:11 ` Stephen Hemminger 2021-07-16 14:28 ` [dpdk-dev] [RFC v2 8/8] test: support ethdev Ferruh Yigit 2023-08-22 21:15 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Stephen Hemminger 7 siblings, 1 reply; 16+ messages in thread From: Ferruh Yigit @ 2021-07-16 14:27 UTC (permalink / raw) To: Andrew Rybchenko, Thomas Monjalon; +Cc: Ferruh Yigit, dev Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- app/test/virtual_pmd.c | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c index 27c8501b96a7..4b8318cf39dd 100644 --- a/app/test/virtual_pmd.c +++ b/app/test/virtual_pmd.c @@ -35,11 +35,35 @@ struct virtual_ethdev_queue { struct rte_eth_rxconf rx_conf; }; +static int +virtual_ethdev_rx_queue_start(struct rte_eth_dev *eth_dev, uint16_t queue_id) +{ + eth_dev->data->rx_queue_state[queue_id] = RTE_ETH_QUEUE_STATE_STARTED; + + return 0; +} + +static int +virtual_ethdev_tx_queue_start(struct rte_eth_dev *eth_dev, uint16_t queue_id) +{ + eth_dev->data->tx_queue_state[queue_id] = RTE_ETH_QUEUE_STATE_STARTED; + + return 0; +} + static int virtual_ethdev_start_success(struct rte_eth_dev *eth_dev) { + int i; + eth_dev->data->dev_started = 1; + for (i = 0; i < eth_dev->data->nb_rx_queues; i++) + virtual_ethdev_rx_queue_start(eth_dev, i); + + for (i = 0; i < eth_dev->data->nb_tx_queues; i++) + virtual_ethdev_tx_queue_start(eth_dev, i); + return 0; } @@ -50,10 +74,34 @@ virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev) return -1; } + +static int +virtual_ethdev_rx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t queue_id) +{ + eth_dev->data->rx_queue_state[queue_id] = RTE_ETH_QUEUE_STATE_STOPPED; + + return 0; +} + +static int +virtual_ethdev_tx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t queue_id) +{ + eth_dev->data->tx_queue_state[queue_id] = RTE_ETH_QUEUE_STATE_STOPPED; + + return 0; +} + static int virtual_ethdev_stop(struct rte_eth_dev *eth_dev) { void *pkt = NULL; struct virtual_ethdev_private *prv = eth_dev->data->dev_private; + int i; + + for (i = 0; i < eth_dev->data->nb_rx_queues; i++) + virtual_ethdev_rx_queue_stop(eth_dev, i); + + for (i = 0; i < eth_dev->data->nb_tx_queues; i++) + virtual_ethdev_tx_queue_stop(eth_dev, i); eth_dev->data->dev_link.link_status = ETH_LINK_DOWN; eth_dev->data->dev_started = 0; @@ -271,6 +319,10 @@ static const struct eth_dev_ops virtual_ethdev_default_dev_ops = { .dev_stop = virtual_ethdev_stop, .dev_close = virtual_ethdev_close, .dev_infos_get = virtual_ethdev_info_get, + .rx_queue_start = virtual_ethdev_rx_queue_start, + .tx_queue_start = virtual_ethdev_tx_queue_start, + .rx_queue_stop = virtual_ethdev_rx_queue_stop, + .tx_queue_stop = virtual_ethdev_tx_queue_stop, .rx_queue_setup = virtual_ethdev_rx_queue_setup_success, .tx_queue_setup = virtual_ethdev_tx_queue_setup_success, .rxq_info_get = virtual_ethdev_rx_info_get, -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [dpdk-dev] [RFC v2 7/8] test/virtual_pmd: support queue start/stop 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 7/8] test/virtual_pmd: support queue start/stop Ferruh Yigit @ 2023-08-22 21:11 ` Stephen Hemminger 0 siblings, 0 replies; 16+ messages in thread From: Stephen Hemminger @ 2023-08-22 21:11 UTC (permalink / raw) To: Ferruh Yigit; +Cc: Andrew Rybchenko, Thomas Monjalon, dev On Fri, 16 Jul 2021 15:27:59 +0100 Ferruh Yigit <ferruh.yigit@intel.com> wrote: > @@ -271,6 +319,10 @@ static const struct eth_dev_ops virtual_ethdev_default_dev_ops = { > .dev_stop = virtual_ethdev_stop, > .dev_close = virtual_ethdev_close, > .dev_infos_get = virtual_ethdev_info_get, > + .rx_queue_start = virtual_ethdev_rx_queue_start, > + .tx_queue_start = virtual_ethdev_tx_queue_start, > + .rx_queue_stop = virtual_ethdev_rx_queue_stop, > + .tx_queue_stop = virtual_ethdev_tx_queue_stop, This part of the patch needs to be rebased, driver now has other bits. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [dpdk-dev] [RFC v2 8/8] test: support ethdev 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit ` (5 preceding siblings ...) 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 7/8] test/virtual_pmd: support queue start/stop Ferruh Yigit @ 2021-07-16 14:28 ` Ferruh Yigit 2023-08-22 21:14 ` Stephen Hemminger 2023-08-22 21:15 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Stephen Hemminger 7 siblings, 1 reply; 16+ messages in thread From: Ferruh Yigit @ 2021-07-16 14:28 UTC (permalink / raw) To: Andrew Rybchenko, Thomas Monjalon; +Cc: Ferruh Yigit, dev Added unit test for ethdev APIs, this unit test 'ethdev_api_autotest' can run without physical device. If there are physical devices probed, they will be ignored by the unit test. A few issues fixed or some clarification added in the ehtdev library with in this unit test patch. Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> --- Notes: * 'rte_eth_dev_owner_unset()' error message is misleading: "Cannot set owner to port 1 already owned by ..." Unset API error message is about setting. * 'rte_eth_dev_owner_delete()' crashes, fixed here but it seems it is not used at all * 'rte_eth_dev_configure()' is too complex, there still much more things to test in that API. * Is there a way to get start/stop status of a port, should we add a new API, 'rte_eth_dev_is_started()', ? * Need a way to get bus from ethdev. Current API requires "rte_device" which is internal information from ethdev perspective. * Clarification added that PMD should implement 'dev_infos_get' for 'rte_eth_dev_configure()' support. * Tried to clarify dev_flags with more comments * In configure, for default config, having only Rx or Tx queue number pass the test but it should fail, adding more checks to 'rte_eth_dev_configure()' for it. * Do we need a way to get device 'dev_conf.rxmode.max_rx_pkt_len' value? * `rte_eth_rx_queue_setup()` fails for multiple Rx mempool and length is not configured (default 0). Changelog: v2: * Because of 'rte_eth_dev_configure()' change, can't start port before configure. And if latest 'rte_eth_dev_configure()' fails can't start port anymore, so last 'rte_eth_dev_configure()' should succeed. * more 'ethdev_rx_queue_setup' tests added. --- app/test/meson.build | 2 + app/test/test.c | 1 + app/test/test_ethdev.c | 1582 ++++++++++++++++++++++++++++++++++ lib/ethdev/ethdev_driver.h | 6 +- lib/ethdev/rte_ethdev.c | 19 +- lib/ethdev/rte_ethdev.h | 16 +- lib/ethdev/rte_ethdev_core.h | 2 +- 7 files changed, 1622 insertions(+), 6 deletions(-) create mode 100644 app/test/test_ethdev.c diff --git a/app/test/meson.build b/app/test/meson.build index a7611686adcb..7f41f2cf5ec0 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -48,6 +48,7 @@ test_sources = files( 'test_efd.c', 'test_efd_perf.c', 'test_errno.c', + 'test_ethdev.c', 'test_ethdev_link.c', 'test_event_crypto_adapter.c', 'test_event_eth_rx_adapter.c', @@ -215,6 +216,7 @@ fast_tests = [ ['eal_fs_autotest', true], ['errno_autotest', true], ['ethdev_link_status', true], + ['ethdev_api_autotest', true], ['event_ring_autotest', true], ['fib_autotest', true], ['fib6_autotest', true], diff --git a/app/test/test.c b/app/test/test.c index 173d202e4774..82727e10b2be 100644 --- a/app/test/test.c +++ b/app/test/test.c @@ -222,6 +222,7 @@ main(int argc, char **argv) break; } cmdline_free(cl); + printf("\n"); goto out; } else { /* if no DPDK_TEST env variable, go interactive */ diff --git a/app/test/test_ethdev.c b/app/test/test_ethdev.c new file mode 100644 index 000000000000..3100d8bbc9b5 --- /dev/null +++ b/app/test/test_ethdev.c @@ -0,0 +1,1582 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#include <inttypes.h> + +#include <rte_ethdev.h> +#include <ethdev_driver.h> + +#include "test.h" +#include "virtual_pmd.h" + +#define MAX_PORT_NUMBER 2 + +static uint16_t port_id[MAX_PORT_NUMBER]; +static struct eth_dev_ops *dev_ops[MAX_PORT_NUMBER]; +static uint16_t initial_port_number; +static uint16_t port_number; +static uint64_t port_owner_id; +static uint16_t invalid_port_id = 999; +static uint16_t default_nb_rx_q = 2; +static uint16_t default_nb_tx_q = 2; + +#define TEST_PMD_NAME "net_test" + +#define MAX_RX_PKTLEN 2048 + +static int +ethdev_api_setup(void) +{ + struct rte_ether_addr mac_addr = { + { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0x00 }, + }; + char name[RTE_ETH_NAME_MAX_LEN]; + uint16_t local_port_id; + int ret; + + if (port_number != 0) + return TEST_SUCCESS; + + initial_port_number = rte_eth_dev_count_total(); + + snprintf(name, RTE_ETH_NAME_MAX_LEN, "%s%d", TEST_PMD_NAME, port_number); + ret = virtual_ethdev_create(name, &mac_addr, rte_socket_id(), 1); + TEST_ASSERT(ret >= 0, "Failed to create test PMD %s\n", name); + local_port_id = (uint16_t)ret; + dev_ops[port_number] = virtual_ethdev_ops_get(local_port_id); + port_id[port_number++] = local_port_id; + + snprintf(name, RTE_ETH_NAME_MAX_LEN, "%s%d", TEST_PMD_NAME, port_number); + ret = virtual_ethdev_create(name, &mac_addr, rte_socket_id(), 1); + TEST_ASSERT(ret >= 0, "Failed to create test PMD %s\n", name); + local_port_id = (uint16_t)ret; + dev_ops[port_number] = virtual_ethdev_ops_get(local_port_id); + port_id[port_number++] = local_port_id; + + return TEST_SUCCESS; +} + +static void +ethdev_api_teardown(void) +{ + int local_port_number = port_number; + char name[RTE_ETH_NAME_MAX_LEN]; + int i; + + for (i = 0; i < local_port_number; i++) { + rte_eth_dev_close(port_id[i]); + snprintf(name, RTE_ETH_NAME_MAX_LEN, "%s%d", TEST_PMD_NAME, i); + /* TODO: get bus from eth_dev */ + rte_eal_hotplug_remove("pci", name); + port_number--; + } + + /* reset global variables */ + memset(port_id, 0, MAX_PORT_NUMBER * sizeof(port_id[0])); + memset(dev_ops, 0, MAX_PORT_NUMBER * sizeof(dev_ops[0])); + port_owner_id = RTE_ETH_DEV_NO_OWNER; +} + +static int +ethdev_count_avail(void) +{ + uint16_t count; + + count = rte_eth_dev_count_avail(); + TEST_ASSERT_EQUAL(count, port_number + initial_port_number, + "Failed to get available ethdev device count\n"); + + return TEST_SUCCESS; +} + +static int +ethdev_owner_get(void) +{ + char no_name[RTE_ETH_MAX_OWNER_NAME_LEN] = ""; + struct rte_eth_dev_owner owner; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + ret = rte_eth_dev_owner_get(invalid_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, + "Owner get accepted invalid port id %u\n", + invalid_port_id); + + ret = rte_eth_dev_owner_get(port_id[i], NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Owner get accepted null owner for port id %u\n", + port_id[i]); + + ret = rte_eth_dev_owner_get(port_id[i], &owner); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to get owner for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(owner.id, RTE_ETH_DEV_NO_OWNER, + "Received owner id doesn't match with no owner id port id %u\n", + port_id[i]); + TEST_ASSERT_BUFFERS_ARE_EQUAL(owner.name, no_name, + RTE_ETH_MAX_OWNER_NAME_LEN, + "Received owner name doesn't match with no owner name port id %u\n", + port_id[i]); + } + + return TEST_SUCCESS; +} + +static int +ethdev_owner_new(void) +{ + uint64_t local_port_owner_id; + int ret; + + /* null owner id pointer */ + ret = rte_eth_dev_owner_new(NULL); + RTE_TEST_ASSERT_FAIL(ret, "NULL owner argument accepted\n"); + + ret = rte_eth_dev_owner_new(&port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get new owner id\n"); + + /* Check not same owner ID received twice */ + local_port_owner_id = port_owner_id; + ret = rte_eth_dev_owner_new(&port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get new owner id\n"); + TEST_ASSERT_NOT_EQUAL(port_owner_id, local_port_owner_id, + "Existing owner id returned\n"); + + return TEST_SUCCESS; +} + +static int +ethdev_owner_set(void) +{ + struct rte_eth_dev_owner owner = { + .id = RTE_ETH_DEV_NO_OWNER, + .name = "TEST", + }; + struct rte_eth_dev_owner owner_get; + uint16_t local_port_id = port_id[1]; + const char *alternate_name = "TEST2"; + int ret; + + /* invalid port id */ + ret = rte_eth_dev_owner_set(invalid_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Owner set accepted invalid port id %u\n", + invalid_port_id); + + /* null owner */ + ret = rte_eth_dev_owner_set(local_port_id, NULL); + RTE_TEST_ASSERT_FAIL(ret, "Owner set accepted null owner for port id %u\n", + local_port_id); + + /* no owner id */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Accepted no owner id for port id %u\n", + local_port_id); + + /* invalid owner id */ + owner.id = port_owner_id + 1; /* 'rte_eth_dev_owner_new() called twice */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Accepted invalid owner id for port id %u\n", + local_port_id); + + /* set owner */ + owner.id = port_owner_id; + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to set owner for port id %u\n", + local_port_id); + + /* get the owner back and verify */ + ret = rte_eth_dev_owner_get(local_port_id, &owner_get); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get owner for port id %u\n", + local_port_id); + TEST_ASSERT_EQUAL(owner.id, owner_get.id, + "Received owner id doesn't match with set owner id port id %u\n", + local_port_id); + TEST_ASSERT_BUFFERS_ARE_EQUAL(owner.name, owner_get.name, + RTE_ETH_MAX_OWNER_NAME_LEN, + "Received owner name doesn't match with set owner name port id %u\n", + local_port_id); + + /* set same owner */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Accepted same owner for port id %u\n", + local_port_id); + + /* no owner id after owner set */ + owner.id = RTE_ETH_DEV_NO_OWNER; + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, "Accepted no owner id for port id %u\n", + local_port_id); + + /* set owner with same owner id different owner name */ + owner.id = port_owner_id; + strlcpy(owner.name, alternate_name, RTE_ETH_MAX_OWNER_NAME_LEN); + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted same owner id different owner name for port id %u\n", + local_port_id); + + /* set owner with same owner name different owner id */ + owner.id = port_owner_id - 1; /* Two owner ids received */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted different owner id with same owner name for port id %u\n", + local_port_id); + + /* Set owner with very large name */ + ret = rte_eth_dev_owner_unset(local_port_id, port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to unset owner for port id %u\n", + local_port_id); + + owner.id = port_owner_id; + memset(owner.name, 'x', RTE_ETH_MAX_OWNER_NAME_LEN); + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to set owner with large name for port id %u\n", + local_port_id); + + /* Force printing the previously set large name */ + ret = rte_eth_dev_owner_set(local_port_id, &owner); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted same owner with large name for port id %u\n", + local_port_id); + + return TEST_SUCCESS; +} + +/* There must be two ethdev devices created at this point, + * But one of them has owner, so available and total device counts + * should differ. + */ +static int +ethdev_count_total(void) +{ + uint16_t total_count; + uint16_t available_count; + uint16_t count; + + total_count = rte_eth_dev_count_total(); + TEST_ASSERT_EQUAL(total_count, initial_port_number + port_number, + "Failed to get total ethdev device count\n"); + + available_count = initial_port_number + port_number - 1; /* One has owner */ + count = rte_eth_dev_count_avail(); + TEST_ASSERT_EQUAL(count, available_count, + "Failed to get available ethdev device count after ownership\n"); + + return TEST_SUCCESS; +} + +static int +ethdev_owner_unset(void) +{ + char no_name[RTE_ETH_MAX_OWNER_NAME_LEN] = ""; + uint16_t local_port_id = port_id[1]; + struct rte_eth_dev_owner owner; + uint64_t invalid_owner_id; + int ret; + + /* unset owner with invalid port id */ + ret = rte_eth_dev_owner_unset(invalid_port_id, port_owner_id); + RTE_TEST_ASSERT_FAIL(ret, "Owner unset accepted invalid port id %u\n", + invalid_port_id); + + /* unset owner with invalid owner id */ + invalid_owner_id = port_owner_id - 1; + ret = rte_eth_dev_owner_unset(local_port_id, invalid_owner_id); + RTE_TEST_ASSERT_FAIL(ret, + "Owner unset accepted invalid owner id %" PRIu64 " for port id %u\n", + invalid_owner_id, local_port_id); + + invalid_owner_id = port_owner_id + 1; + ret = rte_eth_dev_owner_unset(local_port_id, invalid_owner_id); + RTE_TEST_ASSERT_FAIL(ret, + "Owner unset accepted invalid owner id %" PRIu64 " for port id %u\n", + invalid_owner_id, local_port_id); + + /* unset owner */ + ret = rte_eth_dev_owner_unset(local_port_id, port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to unset owner for port id %u\n", + local_port_id); + + /* verify owner unset */ + ret = rte_eth_dev_owner_get(local_port_id, &owner); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get owner for port id %u\n", + local_port_id); + TEST_ASSERT_EQUAL(owner.id, RTE_ETH_DEV_NO_OWNER, + "Received owner id doesn't match with no owner id port id %u\n", + local_port_id); + TEST_ASSERT_BUFFERS_ARE_EQUAL(owner.name, no_name, + RTE_ETH_MAX_OWNER_NAME_LEN, + "Received owner name doesn't match with no owner name port id %u\n", + local_port_id); + + return TEST_SUCCESS; +} + +static int +ethdev_owner_delete(void) +{ + struct rte_eth_dev_owner owner = { + .id = port_owner_id, + .name = "TEST", + }; + uint64_t invalid_owner_id; + int count; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + /* set owner */ + ret = rte_eth_dev_owner_set(port_id[i], &owner); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to set owner for port id %u\n", + port_id[i]); + + /* delete owner with invalid owner id */ + invalid_owner_id = port_owner_id - 1; + ret = rte_eth_dev_owner_unset(port_id[i], invalid_owner_id); + RTE_TEST_ASSERT_FAIL(ret, + "Owner delete accepted invalid owner id %" PRIu64 " for port id %u\n", + invalid_owner_id, port_id[i]); + + invalid_owner_id = port_owner_id + 1; + ret = rte_eth_dev_owner_unset(port_id[i], invalid_owner_id); + RTE_TEST_ASSERT_FAIL(ret, + "Owner delete accepted invalid owner id %" PRIu64 " for port id %u\n", + invalid_owner_id, port_id[i]); + } + + ret = rte_eth_dev_owner_delete(port_owner_id); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to delete owner id %" PRIu64 "\n", + port_owner_id); + + count = rte_eth_dev_count_avail(); + TEST_ASSERT_EQUAL(count, initial_port_number + port_number, + "Failed to delete owner id %" PRIu64 " from some ethdev devices\n", + port_owner_id); + + return TEST_SUCCESS; +} + +static int +configure_fail(struct rte_eth_dev *dev __rte_unused) +{ + return -1; +} + +static int +info_get_default_config(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ +#define DEFAULT_BURST_SIZE 99 +#define DEFAULT_RING_SIZE 129 +#define DEFAULT_QUEUE_NUMBER 333 + struct rte_eth_dev_portconf portconfig = { + .burst_size = DEFAULT_BURST_SIZE, + .ring_size = DEFAULT_RING_SIZE, + .nb_queues = DEFAULT_QUEUE_NUMBER, + }; + dev_info->default_rxportconf = portconfig; + dev_info->default_txportconf = portconfig; + +#define DEFAULT_RX_FREE_THRESH 48 + dev_info->default_rxconf = (struct rte_eth_rxconf) { + .rx_free_thresh = DEFAULT_RX_FREE_THRESH, + }; + +#define DEFAULT_TX_FREE_THRESH 54 + dev_info->default_txconf = (struct rte_eth_txconf) { + .tx_free_thresh = DEFAULT_TX_FREE_THRESH, + }; + + dev_info->max_rx_queues = DEFAULT_QUEUE_NUMBER + 1; + dev_info->max_tx_queues = DEFAULT_QUEUE_NUMBER + 1; + + return 0; +} + +static int +info_get_offload_jumbo(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_pktlen = MAX_RX_PKTLEN; + + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_JUMBO_FRAME; + + return 0; +} + +static int +info_get_min_max_mtu(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_pktlen = MAX_RX_PKTLEN; + + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_JUMBO_FRAME; + + dev_info->min_mtu = RTE_ETHER_MIN_MTU; + dev_info->max_mtu = MAX_RX_PKTLEN - 100; + + return 0; +} + +static int +info_get_lro(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_TCP_LRO; + + return 0; +} + +static int +info_get_lro_pkt_size(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ +#define MAX_LRO_PKTLEN (MAX_RX_PKTLEN * 2) + dev_info->max_lro_pkt_size = MAX_LRO_PKTLEN; + + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_TCP_LRO; + + return 0; +} + +static int +info_get_rss_hash_offload(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_RSS_HASH; + + return 0; +} + +static int +ethdev_configure(void) +{ + struct eth_dev_ops *local_dev_ops; + struct eth_dev_ops backup_dev_ops; + struct rte_eth_dev_info dev_info; + struct rte_eth_conf dev_conf; + uint16_t nb_rx_q = 0; + uint16_t nb_tx_q = 0; + int ret; + int i; + + memset(&dev_conf, 0, sizeof(dev_conf)); + + for (i = 0; i < port_number; i++) { + /* invalid port id */ + ret = rte_eth_dev_configure(invalid_port_id, nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Configure accepted invalid port id %u\n", + invalid_port_id); + + /* set NULL config */ + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL configuration for port id %u\n", + port_id[i]); + + /* no configure dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_configure = NULL; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL configuration for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* no infos_get dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = NULL; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL info get dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* failing dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_configure = configure_fail; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted failing device configuration for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* start before configure */ + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Started before configure for port id %u\n", + port_id[i]); + + /* get device info for various tests below */ + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + + /* set big Rx queue number */ + nb_rx_q = RTE_MAX_QUEUES_PER_PORT + 1; + nb_tx_q = default_nb_tx_q; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue number > RTE_MAX_QUEUES configuration for port id %u\n", + port_id[i]); + + nb_rx_q = dev_info.max_rx_queues + 1; + nb_tx_q = default_nb_tx_q; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue number > max_rx_queues configuration for port id %u\n", + port_id[i]); + + /* set big Tx queue number */ + nb_rx_q = default_nb_rx_q; + nb_tx_q = RTE_MAX_QUEUES_PER_PORT + 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Tx queue number > RTE_MAX_QUEUES configuration for port id %u\n", + port_id[i]); + + nb_rx_q = default_nb_rx_q; + nb_tx_q = dev_info.max_tx_queues + 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Tx queue number > max_tx_queues configuration for port id %u\n", + port_id[i]); + nb_rx_q = default_nb_rx_q; + nb_tx_q = default_nb_tx_q; + + /* request default queue number only for Rx or Tx */ + nb_rx_q = default_nb_rx_q; + nb_tx_q = 0; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted only Tx default queue number for port id %u\n", + port_id[i]); + + nb_rx_q = 0; + nb_tx_q = default_nb_tx_q; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted only Rx default queue number for port id %u\n", + port_id[i]); + nb_rx_q = default_nb_rx_q; + nb_tx_q = default_nb_tx_q; + + /* request not supported LSC */ + dev_conf.intr_conf.lsc = 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted LSC interrupt config port id %u\n", + port_id[i]); + dev_conf.intr_conf.lsc = 0; + + /* request not supported RMV */ + dev_conf.intr_conf.rmv = 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted LSC interrupt config port id %u\n", + port_id[i]); + dev_conf.intr_conf.rmv = 0; + + /* configure device */ + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + + /* configure after start */ + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start port id %u\n", + port_id[i]); + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Configuring an already started port id %u\n", + port_id[i]); + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop port id %u\n", + port_id[i]); + + /* requested supported device features */ + virtual_ethdev_set_dev_flags(port_id[i], + RTE_ETH_DEV_INTR_LSC | RTE_ETH_DEV_INTR_RMV); + dev_conf.intr_conf.lsc = 1; + dev_conf.intr_conf.rmv = 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to configure with device flags for port id %u\n", + port_id[i]); + dev_conf.intr_conf.lsc = 0; + dev_conf.intr_conf.rmv = 0; + + /* Use default Rx/Tx queue numbers */ + nb_rx_q = 0; + nb_tx_q = 0; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.nb_rx_queues, + RTE_ETH_DEV_FALLBACK_RX_NBQUEUES, + "Default Rx queue number is wrong for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.nb_tx_queues, + RTE_ETH_DEV_FALLBACK_TX_NBQUEUES, + "Default Tx queue number is wrong for port id %u\n", + port_id[i]); + nb_rx_q = default_nb_rx_q; + nb_tx_q = default_nb_tx_q; + + /* Use PMD provided Rx/Tx queue numbers */ + nb_rx_q = 0; + nb_tx_q = 0; + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_default_config; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.nb_rx_queues, DEFAULT_QUEUE_NUMBER, + "Default driver Rx queue number is wrong for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.nb_tx_queues, DEFAULT_QUEUE_NUMBER, + "Default driver Tx queue number is wrong for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + nb_rx_q = default_nb_rx_q; + nb_tx_q = default_nb_tx_q; + + /* check max_rx_pkt_len without jumbo frame support */ + uint16_t overhead_len; + struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id[i]]; + overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; + dev_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MTU + overhead_len + 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + TEST_ASSERT_NOT_EQUAL(eth_dev->data->dev_conf.rxmode.max_rx_pkt_len, + dev_conf.rxmode.max_rx_pkt_len, + "Accepted Rx packet length bigger than max MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(eth_dev->data->dev_conf.rxmode.max_rx_pkt_len, + (uint32_t)(RTE_ETHER_MTU + overhead_len), + "Max Rx packet length calculated wrong for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + + dev_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MIN_MTU + overhead_len - 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + TEST_ASSERT_NOT_EQUAL(eth_dev->data->dev_conf.rxmode.max_rx_pkt_len, + dev_conf.rxmode.max_rx_pkt_len, + "Accepted Rx packet length less than min MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(eth_dev->data->dev_conf.rxmode.max_rx_pkt_len, + (uint32_t)(RTE_ETHER_MTU + overhead_len), + "Max Rx packet length calculated wrong for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + + /* check max_rx_pkt_len with jumbo frame support */ + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN + 1; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted Rx packet length bigger than supported by device for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + + dev_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MIN_LEN - 1; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted Rx packet length less than min MTU for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + + uint16_t mtu; + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_offload_jumbo; + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_get_mtu(port_id[i], &mtu); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_conf.rxmode.max_rx_pkt_len - overhead_len, + mtu, + "MTU calculated wrong on configure for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + *local_dev_ops = backup_dev_ops; + + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_offload_jumbo; + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_get_mtu(port_id[i], &mtu); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_conf.rxmode.max_rx_pkt_len - overhead_len, + mtu, + "MTU calculated wrong on configure for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + *local_dev_ops = backup_dev_ops; + + /* max_rx_pkt_len with jumbo frame with min/max MTU */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_min_max_mtu; + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + overhead_len = dev_info.max_rx_pktlen - dev_info.max_mtu; + ret = rte_eth_dev_get_mtu(port_id[i], &mtu); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get MTU for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_conf.rxmode.max_rx_pkt_len - overhead_len, + mtu, + "MTU calculated wrong on configure for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + *local_dev_ops = backup_dev_ops; + + /* LRO */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_lro; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_TCP_LRO; + dev_conf.rxmode.max_lro_pkt_size = MAX_RX_PKTLEN * 2; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted different LRO packet size when driver limit is missing for port id %u\n", + port_id[i]); + dev_conf.rxmode.offloads = 0; + dev_conf.rxmode.max_lro_pkt_size = 0; + *local_dev_ops = backup_dev_ops; + + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_lro_pkt_size; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_TCP_LRO; + dev_conf.rxmode.max_lro_pkt_size = MAX_LRO_PKTLEN + 1; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted LRO packet size bigger than what device supports for port id %u\n", + port_id[i]); + dev_conf.rxmode.offloads = 0; + dev_conf.rxmode.max_lro_pkt_size = 0; + *local_dev_ops = backup_dev_ops; + + /* offloads */ + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_JUMBO_FRAME; + dev_conf.rxmode.max_rx_pkt_len = MAX_RX_PKTLEN; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted offload that is not in the capability for port id %u\n", + port_id[i]); + dev_conf.rxmode.max_rx_pkt_len = 0; + dev_conf.rxmode.offloads = 0; + + /* RSS hash function */ + dev_conf.rx_adv_conf.rss_conf.rss_hf = ETH_RSS_ETH; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted RSS hash function that is not in the capability for port id %u\n", + port_id[i]); + dev_conf.rx_adv_conf.rss_conf.rss_hf = 0; + + /* RSS hash offload */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_rss_hash_offload; + dev_conf.rxmode.offloads = DEV_RX_OFFLOAD_RSS_HASH; + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted RSS hash offload without RSS for port id %u\n", + port_id[i]); + dev_conf.rxmode.offloads = 0; + *local_dev_ops = backup_dev_ops; + + /* start after failed configure */ + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Started after failed configure for port id %u\n", + port_id[i]); + + /* Need successful configure for start */ + ret = rte_eth_dev_configure(port_id[i], nb_rx_q, nb_tx_q, + &dev_conf); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure port id %u\n", + port_id[i]); + } + + // rss_hf src_only and dst_only + // eth_dev_tx_queue_config + // eth_dev_rx_queue_config + // RTE_ETHDEV_PROFILE_WITH_VTUNE + // eth_dev_validate_offloads + // restore config + // restore mtu + + return TEST_SUCCESS; +} + + +static const char *virtual_ethdev_driver_name = "Virtual PMD"; +static int +info_get_success(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 = MAX_RX_PKTLEN; + + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->min_rx_bufsize = 0; + + return 0; +} + +static int +info_get_fail(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info __rte_unused) +{ + return -1; +} + +static int +info_get_max_queues(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->max_rx_queues = RTE_MAX_QUEUES_PER_PORT + 1; + dev_info->max_tx_queues = RTE_MAX_QUEUES_PER_PORT + 1; + + return 0; +} + +static int +info_get_mtu(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ +#define MIN_MTU 256 +#define MAX_MTU 512 + dev_info->min_mtu = MIN_MTU; + dev_info->max_mtu = MAX_MTU; + + return 0; +} + +static int +ethdev_info_get(void) +{ + struct eth_dev_ops *local_dev_ops; + struct eth_dev_ops backup_dev_ops; + struct rte_eth_dev_info dev_info; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + /* invalid port id */ + ret = rte_eth_dev_info_get(invalid_port_id, &dev_info); + RTE_TEST_ASSERT_FAIL(ret, + "Getting info accepted invalid port id %u\n", + invalid_port_id); + + /* NULL info */ + ret = rte_eth_dev_info_get(port_id[i], NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL info struct for port id %u\n", + port_id[i]); + + /* no infos_get dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = NULL; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL info get dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* failing dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_fail; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted failing device info get for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* get info */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_success; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* big max queues number */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_max_queues; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_NOT_EQUAL(dev_info.nb_rx_queues, RTE_MAX_QUEUES_PER_PORT + 1, + "Accepted big Rx queue number for port id %u\n", + port_id[i]); + TEST_ASSERT_NOT_EQUAL(dev_info.nb_tx_queues, RTE_MAX_QUEUES_PER_PORT + 1, + "Accepted big Tx queue number for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* min/max MTU */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_mtu; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.min_mtu, MIN_MTU, + "Received min MTU is wrong for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(dev_info.max_mtu, MAX_MTU, + "Received max MTU is wrong for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* verify dev_flags */ +#define DEV_FLAG 0xABCD + uint32_t local_dev_flag = DEV_FLAG; + virtual_ethdev_set_dev_flags(port_id[i], local_dev_flag); + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get info for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(*dev_info.dev_flags, local_dev_flag, + "Received device flags is wrong for port id %u\n", + port_id[i]); + } + + return TEST_SUCCESS; +} + +static int +info_get_multi_rx_segment(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->rx_seg_capa.max_nseg = 3; + dev_info->rx_queue_offload_capa = RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT; + dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT; + dev_info->rx_seg_capa.multi_pools = 0; + + return 0; +} + +static int +info_get_large_min_rx_bufsize(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->min_rx_bufsize = RTE_MBUF_DEFAULT_BUF_SIZE; + + return 0; +} + +static int +info_get_runtime_rx_setup(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP; + + return 0; +} + +static int +ethdev_rx_queue_setup(void) +{ + struct rte_eth_rxconf rx_conf; + uint16_t rx_queue_id = 0; + uint16_t nb_rx_desc = 256; + unsigned int socket_id = SOCKET_ID_ANY; + struct rte_mempool *mp = NULL; + struct rte_mempool *first_seg_mp = NULL; + struct rte_mempool *second_seg_mp = NULL; + struct eth_dev_ops *local_dev_ops; + struct eth_dev_ops backup_dev_ops; + struct rte_eth_dev_info dev_info; + int ret; + int i; + + memset(&rx_conf, 0, sizeof(struct rte_eth_rxconf)); + mp = rte_pktmbuf_pool_create("test_ethdev", 128, 0, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + + for (i = 0; i < port_number; i++) { + /* invalid port id */ + ret = rte_eth_rx_queue_setup(invalid_port_id, rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted invalid port id %u\n", + invalid_port_id); + + /* invalid queue id */ + rx_queue_id = default_nb_rx_q; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted invalid port id %u\n", + port_id[i]); + rx_queue_id = 0; + + /* no rx_queue_setup dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->rx_queue_setup = NULL; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL Rx queue setup dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* no infos_get dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = NULL; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL info get dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* failing infos_get dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_fail; + ret = rte_eth_dev_info_get(port_id[i], &dev_info); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted failing device info get for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* null mp with null rx_conf */ + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, NULL, NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted null mempool with null config for port id %u\n", + port_id[i]); + + /* null mp with null rx_seg */ + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted null mempool with null rx_seg for port id %u\n", + port_id[i]); + + union rte_eth_rxseg rxseg[2]; + memset(&rxseg, 0, sizeof(union rte_eth_rxseg) * 2); + /* null mp with zero rx_nseg */ + rx_conf.rx_seg = &rxseg[0]; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted null mempool with zero rx_nseg for port id %u\n", + port_id[i]); + rx_conf.rx_seg = NULL; + + /* null mp without RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT offload */ + rx_conf.rx_seg = &rxseg[0]; + rx_conf.rx_nseg = 1; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted null mempool without split offload for port id %u\n", + port_id[i]); + rx_conf.rx_seg = NULL; + rx_conf.rx_nseg = 0; + + /* null mp with rx_nseg > seg_capa->max_nseg */ + rx_conf.rx_seg = &rxseg[0]; + rx_conf.rx_nseg = 1; + rx_conf.offloads |= RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted null mempool with segment " + "number bigger than supported for port id %u\n", + port_id[i]); + rx_conf.rx_seg = NULL; + rx_conf.rx_nseg = 0; + rx_conf.offloads = 0; + + /* null mp with null segment mp */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_multi_rx_segment; + rx_conf.rx_seg = &rxseg[0]; + rx_conf.rx_nseg = 1; + rx_conf.offloads |= RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted null mempool with null segment mempool for port id %u\n", + port_id[i]); + rx_conf.rx_seg = NULL; + rx_conf.rx_nseg = 0; + rx_conf.offloads = 0; + *local_dev_ops = backup_dev_ops; + + /* null mp with segment mp are different when not supported */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_multi_rx_segment; + first_seg_mp = rte_pktmbuf_pool_create("test_ethdev1", 128, 0, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + second_seg_mp = rte_pktmbuf_pool_create("test_ethdev2", 128, 0, 0, + RTE_MBUF_DEFAULT_BUF_SIZE - 512, rte_socket_id()); + rx_conf.rx_seg = rxseg; + rxseg[0].split.mp = first_seg_mp; + rxseg[0].split.length = 512; + //TODO: when rxseg.split.length is 0, API fails, check it + rxseg[1].split.mp = second_seg_mp; + rxseg[1].split.length = 512; + rx_conf.rx_nseg = 2; + rx_conf.offloads |= RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, NULL); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted null mempool with segment mp " + "are different when not supported for port id %u\n", + port_id[i]); + rx_conf.rx_seg = NULL; + rx_conf.rx_nseg = 0; + rx_conf.offloads = 0; + *local_dev_ops = backup_dev_ops; + memset(&rxseg, 0, sizeof(union rte_eth_rxseg) * 2); + rte_mempool_free(first_seg_mp); + first_seg_mp = NULL; + rte_mempool_free(second_seg_mp); + second_seg_mp = NULL; + + //TODO: Add more segment Rx tests based on other capabilities + + /* mp with non zero Rx segment number */ + rx_conf.rx_seg = &rxseg[0]; + rx_conf.rx_nseg = 1; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted mempool with non zero rx_nseg for port id %u\n", + port_id[i]); + rx_conf.rx_seg = NULL; + rx_conf.rx_nseg = 0; + + /* mp with buffer size < min buffer size */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_large_min_rx_bufsize; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted mempool with buffer size < min_rx_bufsize for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* Use driver provided default Rx descriptor number */ + struct rte_eth_rxq_info rxq_info; + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_default_config; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + 0, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_SUCCESS(ret, + "Rx queue setup failed for port id %u\n", + port_id[i]); + ret = rte_eth_rx_queue_info_get(port_id[i], rx_queue_id, &rxq_info); + RTE_TEST_ASSERT_SUCCESS(ret, + "Rx queue info get failed for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(rxq_info.nb_desc, DEFAULT_RING_SIZE, + "Not using default Rx desc number on Rx queue setup for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* Use library default Rx descriptor number */ + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + 0, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_SUCCESS(ret, + "Rx queue setup failed for port id %u\n", + port_id[i]); + ret = rte_eth_rx_queue_info_get(port_id[i], rx_queue_id, &rxq_info); + RTE_TEST_ASSERT_SUCCESS(ret, + "Rx queue info get failed for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(rxq_info.nb_desc, RTE_ETH_DEV_FALLBACK_RX_RINGSIZE, + "Not using default Rx desc number on Rx queue setup for port id %u\n", + port_id[i]); + + /* Rx descriptor less than min supported by driver */ + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + VIRTUAL_ETHDEV_MIN_DESC_NUM - 1, + socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted Rx descriptor less than supported for port id %u\n", + port_id[i]); + + /* Rx descriptor more than max supported by driver */ + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + VIRTUAL_ETHDEV_MAX_DESC_NUM + 1, + socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted Rx descriptor more than supported for port id %u\n", + port_id[i]); + + /* Rx descriptor number unaligned */ + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc + VIRTUAL_ETHDEV_DESC_ALIGN + 1, + socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted unaligned number of Rx descriptor for port id %u\n", + port_id[i]); + + /* Setup after port start */ + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start port id %u\n", + port_id[i]); + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted after start for port id %u\n", + port_id[i]); + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop port id %u\n", + port_id[i]); + + /* Setup with runtime setup capability but queue is not stopped */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_runtime_rx_setup; + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start port id %u\n", + port_id[i]); + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup with runtime setup capability accepted " + "started queue for port id %u\n", + port_id[i]); + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* Setup Rx queue when queue is already allocated but there is + * no rx_queue_release dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->rx_queue_release = NULL; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Rx queue setup accepted null queue release dev_ops when " + "queue is already allocated for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* Use driver provided Rx configuration */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_infos_get = info_get_default_config; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, NULL, mp); + RTE_TEST_ASSERT_SUCCESS(ret, + "Rx queue setup failed for port id %u\n", + port_id[i]); + ret = rte_eth_rx_queue_info_get(port_id[i], rx_queue_id, &rxq_info); + RTE_TEST_ASSERT_SUCCESS(ret, + "Rx queue info get failed for port id %u\n", + port_id[i]); + TEST_ASSERT_EQUAL(rxq_info.conf.rx_free_thresh, DEFAULT_RX_FREE_THRESH, + "Not using default Rx config on Rx queue setup for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* Request unsupported Rx queue offload */ + /* expectation is there is no Rx queue specific offload + * capability reported for device and following offload not + * enabled in the port configure */ + rx_conf.offloads = DEV_RX_OFFLOAD_VLAN_STRIP; + ret = rte_eth_rx_queue_setup(port_id[i], rx_queue_id, + nb_rx_desc, socket_id, &rx_conf, mp); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted unsupported Rx queue offload for port id %u\n", + port_id[i]); + rx_conf.offloads = 0; + + //TODO: LRO + + /* Check min Rx buffer size */ + struct rte_eth_dev_data *data; + uint32_t size = RTE_MBUF_DEFAULT_BUF_SIZE; + for (int j = 0; j < default_nb_rx_q; j++) { + size -= 256; + first_seg_mp = rte_pktmbuf_pool_create("test_ethdev1", + 128, 0, 0, size, rte_socket_id()); + ret = rte_eth_rx_queue_setup(port_id[i], j, nb_rx_desc, + socket_id, &rx_conf, first_seg_mp); + RTE_TEST_ASSERT_SUCCESS(ret, + "Rx queue setup failed for port id %u\n", + port_id[i]); + rte_mempool_free(first_seg_mp); + first_seg_mp = NULL; + } + virtual_ethdev_get_dev_data(port_id[i], &data); + TEST_ASSERT_EQUAL(data->min_rx_buf_size, size, + "Rx queue setup set minimum Rx buffer size wrong for port id %u\n", + port_id[i]); + data = NULL; + size = 0; + } + + rte_mempool_free(mp); + + return TEST_SUCCESS; +} + +static int +ethdev_tx_queue_setup(void) +{ + return TEST_SUCCESS; +} + +static int +start_fail(struct rte_eth_dev *dev __rte_unused) +{ + return -1; +} + +static int +ethdev_start(void) +{ + struct eth_dev_ops *local_dev_ops; + struct eth_dev_ops backup_dev_ops; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + /* invalid port id */ + ret = rte_eth_dev_start(invalid_port_id); + RTE_TEST_ASSERT_FAIL(ret, "Start accepted invalid port id %u\n", + invalid_port_id); + + /* no dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_start = NULL; + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL start dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* failing dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_start = start_fail; + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted failing device start for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start port id %u\n", + port_id[i]); + + ret = rte_eth_dev_start(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to start already started port id %u\n", + port_id[i]); + } + + return TEST_SUCCESS; +} + +static int +stop_fail(struct rte_eth_dev *dev __rte_unused) +{ + return -1; +} + +static int +ethdev_stop(void) +{ + struct eth_dev_ops *local_dev_ops; + struct eth_dev_ops backup_dev_ops; + int ret; + int i; + + for (i = 0; i < port_number; i++) { + /* invalid port id */ + ret = rte_eth_dev_stop(invalid_port_id); + RTE_TEST_ASSERT_FAIL(ret, "Stop accepted invalid port id %u\n", + invalid_port_id); + + /* no dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_stop = NULL; + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted NULL stop dev_ops for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + /* failing dev_ops */ + local_dev_ops = dev_ops[i]; + backup_dev_ops = *local_dev_ops; + local_dev_ops->dev_stop = stop_fail; + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_FAIL(ret, + "Accepted failing device stop for port id %u\n", + port_id[i]); + *local_dev_ops = backup_dev_ops; + + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop port id %u\n", + port_id[i]); + + ret = rte_eth_dev_stop(port_id[i]); + RTE_TEST_ASSERT_SUCCESS(ret, + "Failed to stop already stopped port id %u\n", + port_id[i]); + } + + return TEST_SUCCESS; +} + +static int +ethdev_rx_queue_info_get(void) +{ + return TEST_SUCCESS; +} + +static int +ethdev_tx_queue_info_get(void) +{ + return TEST_SUCCESS; +} + +static struct unit_test_suite ethdev_api_testsuite = { + .suite_name = "ethdev API unit test suite", + .setup = ethdev_api_setup, + .teardown = ethdev_api_teardown, + .unit_test_cases = { + TEST_CASE(ethdev_count_avail), + TEST_CASE(ethdev_owner_get), + TEST_CASE(ethdev_owner_new), + TEST_CASE(ethdev_owner_set), + TEST_CASE(ethdev_count_total), + TEST_CASE(ethdev_owner_unset), + TEST_CASE(ethdev_owner_delete), + TEST_CASE(ethdev_configure), + TEST_CASE(ethdev_info_get), + TEST_CASE(ethdev_rx_queue_setup), + TEST_CASE(ethdev_tx_queue_setup), + TEST_CASE(ethdev_rx_queue_info_get), + TEST_CASE(ethdev_tx_queue_info_get), + TEST_CASE(ethdev_start), + TEST_CASE(ethdev_stop), + TEST_CASES_END(), + }, +}; + +static int +test_ethdev_api(void) +{ + return unit_test_suite_runner(ðdev_api_testsuite); +} + +REGISTER_TEST_COMMAND(ethdev_api_autotest, test_ethdev_api); diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h index 40e474aa7e7f..926bf96b719f 100644 --- a/lib/ethdev/ethdev_driver.h +++ b/lib/ethdev/ethdev_driver.h @@ -31,7 +31,11 @@ struct rte_hairpin_peer_info; */ typedef int (*eth_dev_configure_t)(struct rte_eth_dev *dev); -/**< @internal Ethernet device configuration. */ +/**< @internal Ethernet device configuration. + * + * For ``rte_eth_dev_configure()`` API both ``eth_dev_configure_t`` and + * ``eth_dev_infos_get_t`` needs to be implemented by PMD. + * */ typedef int (*eth_dev_start_t)(struct rte_eth_dev *dev); /**< @internal Function used to start a configured Ethernet device. */ diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c index 9d95cd11e1b5..972d332e94d2 100644 --- a/lib/ethdev/rte_ethdev.c +++ b/lib/ethdev/rte_ethdev.c @@ -694,6 +694,7 @@ eth_dev_owner_set(const uint16_t port_id, const uint64_t old_owner_id, } /* can not truncate (same structure) */ + memset(port_owner->name, 0, RTE_ETH_MAX_OWNER_NAME_LEN); strlcpy(port_owner->name, new_owner->name, RTE_ETH_MAX_OWNER_NAME_LEN); port_owner->id = new_owner->id; @@ -748,10 +749,13 @@ rte_eth_dev_owner_delete(const uint64_t owner_id) rte_spinlock_lock(ð_dev_shared_data->ownership_lock); if (eth_is_valid_owner_id(owner_id)) { - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (rte_eth_devices[port_id].data->owner.id == owner_id) - memset(&rte_eth_devices[port_id].data->owner, 0, + for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { + struct rte_eth_dev_data *data = + rte_eth_devices[port_id].data; + if (data != NULL && data->owner.id == owner_id) + memset(&data->owner, 0, sizeof(struct rte_eth_dev_owner)); + } RTE_ETHDEV_LOG(NOTICE, "All port owners owned by %016"PRIx64" identifier have removed\n", owner_id); @@ -1394,6 +1398,15 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q, * If driver does not provide any preferred valued, fall back on * EAL defaults. */ + if ((nb_rx_q & nb_tx_q) == 0 && (nb_rx_q | nb_tx_q) != 0) { + RTE_ETHDEV_LOG(ERR, + "Ethdev port_id (%u), Rx queue number (%u) and Tx queue number (%u) " + "should be both zero or both non-zero\n", + port_id, nb_rx_q, nb_tx_q); + ret = -EINVAL; + goto rollback; + } + if (nb_rx_q == 0 && nb_tx_q == 0) { nb_rx_q = dev_info.default_rxportconf.nb_queues; if (nb_rx_q == 0) diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h index d2b27c351fdb..6ab818b59f66 100644 --- a/lib/ethdev/rte_ethdev.h +++ b/lib/ethdev/rte_ethdev.h @@ -1837,6 +1837,10 @@ struct rte_eth_dev_owner { char name[RTE_ETH_MAX_OWNER_NAME_LEN]; /**< The owner name. */ }; +/** + * Device flags set on ``eth_dev->data->dev_flags`` by drivers. + * These values can be received via ``rte_eth_dev_info_get()`` + */ /** PMD supports thread-safe flow operations */ #define RTE_ETH_DEV_FLOW_OPS_THREAD_SAFE 0x0001 /** Device supports link state interrupt */ @@ -1980,6 +1984,10 @@ int rte_eth_dev_owner_new(uint64_t *owner_id); * * Set an Ethernet device owner. * + * Once an owner is set for an Ethernet device, setting owner again will fail, + * even it is exact same owner. + * Owner ids not obtained by ``rte_eth_dev_owner_new()`` are rejected. + * * @param port_id * The identifier of the port to own. * @param owner @@ -2212,6 +2220,8 @@ rte_eth_dev_is_removed(uint16_t port_id); * - -ENOMEM: Unable to allocate the receive ring descriptors or to * allocate network memory buffers from the memory pool when * initializing receive descriptors. + * - -ENOTSUP: The function or ``rte_eth_dev_info_get()`` is not supported by + * driver. */ int rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id, uint16_t nb_rx_desc, unsigned int socket_id, @@ -2524,6 +2534,8 @@ int rte_eth_dev_tx_queue_stop(uint16_t port_id, uint16_t tx_queue_id); * On success, all basic functions exported by the Ethernet API (link status, * receive/transmit, and so on) can be invoked. * + * Starting an already started port returns success. + * * @param port_id * The port identifier of the Ethernet device. * @return @@ -2536,6 +2548,8 @@ int rte_eth_dev_start(uint16_t port_id); * Stop an Ethernet device. The device can be restarted with a call to * rte_eth_dev_start() * + * Stopping an already stopped port returns success. + * * @param port_id * The port identifier of the Ethernet device. * @return @@ -3036,7 +3050,7 @@ int rte_eth_macaddr_get(uint16_t port_id, struct rte_ether_addr *mac_addr); * min_mtu = RTE_ETHER_MIN_MTU * max_mtu = UINT16_MAX * - * The following fields will be populated if support for dev_infos_get() + *ops The following fields will be populated if support for dev_infos_get() * exists for the device and the rte_eth_dev 'dev' has been populated * successfully with a call to it: * diff --git a/lib/ethdev/rte_ethdev_core.h b/lib/ethdev/rte_ethdev_core.h index edf96de2dc2e..291b70a8cfc4 100644 --- a/lib/ethdev/rte_ethdev_core.h +++ b/lib/ethdev/rte_ethdev_core.h @@ -176,7 +176,7 @@ struct rte_eth_dev_data { /**< Queues state: HAIRPIN(2) / STARTED(1) / STOPPED(0). */ uint8_t tx_queue_state[RTE_MAX_QUEUES_PER_PORT]; /**< Queues state: HAIRPIN(2) / STARTED(1) / STOPPED(0). */ - uint32_t dev_flags; /**< Capabilities. */ + uint32_t dev_flags; /**< Device flags */ int numa_node; /**< NUMA node connection. */ struct rte_vlan_filter_conf vlan_filter_conf; /**< VLAN filter configuration. */ -- 2.31.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [dpdk-dev] [RFC v2 8/8] test: support ethdev 2021-07-16 14:28 ` [dpdk-dev] [RFC v2 8/8] test: support ethdev Ferruh Yigit @ 2023-08-22 21:14 ` Stephen Hemminger 0 siblings, 0 replies; 16+ messages in thread From: Stephen Hemminger @ 2023-08-22 21:14 UTC (permalink / raw) To: Ferruh Yigit; +Cc: Andrew Rybchenko, Thomas Monjalon, dev On Fri, 16 Jul 2021 15:28:00 +0100 Ferruh Yigit <ferruh.yigit@intel.com> wrote: > +/** > + * Device flags set on ``eth_dev->data->dev_flags`` by drivers. > + * These values can be received via ``rte_eth_dev_info_get()`` > + */ Already done in later patches. > @@ -3036,7 +3050,7 @@ int rte_eth_macaddr_get(uint16_t port_id, struct rte_ether_addr *mac_addr); > * min_mtu = RTE_ETHER_MIN_MTU > * max_mtu = UINT16_MAX > * > - * The following fields will be populated if support for dev_infos_get() > + *ops The following fields will be populated if support for dev_infos_get() Typo, just don't change this. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit ` (6 preceding siblings ...) 2021-07-16 14:28 ` [dpdk-dev] [RFC v2 8/8] test: support ethdev Ferruh Yigit @ 2023-08-22 21:15 ` Stephen Hemminger 7 siblings, 0 replies; 16+ messages in thread From: Stephen Hemminger @ 2023-08-22 21:15 UTC (permalink / raw) To: Ferruh Yigit; +Cc: Andrew Rybchenko, Thomas Monjalon, dev On Fri, 16 Jul 2021 15:27:53 +0100 Ferruh Yigit <ferruh.yigit@intel.com> wrote: > Not cleaning the rings prevents creating devices again, which breaks to > run some unit tests multiple times. > > Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> Is this patch set still worth doing? If so it needs to be rebased, updated, and retested. Marking it as changes requested. ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2023-08-22 21:15 UTC | newest] Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-06-17 8:14 [dpdk-dev] [RFC 1/4] test/virtual_pmd: enable getting device operations Ferruh Yigit 2021-06-17 8:14 ` [dpdk-dev] [RFC 2/4] test/virtual_pmd: clean rings on close Ferruh Yigit 2021-06-17 8:14 ` [dpdk-dev] [RFC 3/4] test/virtual_pmd: enable updating device flags Ferruh Yigit 2021-06-17 8:14 ` [dpdk-dev] [RFC 4/4] test: support ethdev Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 2/8] test/virtual_pmd: enable getting device operations Ferruh Yigit 2023-08-22 21:10 ` Stephen Hemminger 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 3/8] test/virtual_pmd: enable updating device flags Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 4/8] test/virtual_pmd: enable getting device data Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 5/8] test/virtual_pmd: support get queue info device ops Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 6/8] test/virtual_pmd: provide descriptor limit info Ferruh Yigit 2021-07-16 14:27 ` [dpdk-dev] [RFC v2 7/8] test/virtual_pmd: support queue start/stop Ferruh Yigit 2023-08-22 21:11 ` Stephen Hemminger 2021-07-16 14:28 ` [dpdk-dev] [RFC v2 8/8] test: support ethdev Ferruh Yigit 2023-08-22 21:14 ` Stephen Hemminger 2023-08-22 21:15 ` [dpdk-dev] [RFC v2 1/8] test/virtual_pmd: clean rings on close Stephen Hemminger
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).