From ecc5f43396150def05f8e9b9271bf687b31c6615 Mon Sep 17 00:00:00 2001 From: Cristian Dumitrescu Date: Thu, 1 Oct 2020 11:20:01 +0100 Subject: [PATCH] port: add ethernet device SWX port Add the Ethernet device input/output port type for the SWX pipeline. Used under the hood by the pipeline rx and tx instructions. Signed-off-by: Cristian Dumitrescu --- doc/api/doxy-api-index.md | 3 +- lib/librte_port/meson.build | 6 +- lib/librte_port/rte_port_version.map | 6 +- lib/librte_port/rte_swx_port_ethdev.c | 313 ++++++++++++++++++++++++++ lib/librte_port/rte_swx_port_ethdev.h | 54 +++++ 5 files changed, 378 insertions(+), 4 deletions(-) create mode 100644 lib/librte_port/rte_swx_port_ethdev.c create mode 100644 lib/librte_port/rte_swx_port_ethdev.h diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index ace8ec6b70..9b3b038ddf 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -171,7 +171,8 @@ The public API headers are grouped by topics: [extern] (@ref rte_swx_extern.h), [pipeline] (@ref rte_swx_pipeline.h) * SWX port: - [port] (@ref rte_swx_port.h) + [port] (@ref rte_swx_port.h), + [ethdev] (@ref rte_swx_port_ethdev.h) * SWX table: [table] (@ref rte_swx_table.h) * [graph] (@ref rte_graph.h): diff --git a/lib/librte_port/meson.build b/lib/librte_port/meson.build index 5b5fbf6c40..3d7f309bb0 100644 --- a/lib/librte_port/meson.build +++ b/lib/librte_port/meson.build @@ -10,7 +10,8 @@ sources = files( 'rte_port_sched.c', 'rte_port_source_sink.c', 'rte_port_sym_crypto.c', - 'rte_port_eventdev.c') + 'rte_port_eventdev.c', + 'rte_swx_port_ethdev.c',) headers = files( 'rte_port_ethdev.h', 'rte_port_fd.h', @@ -22,7 +23,8 @@ headers = files( 'rte_port_source_sink.h', 'rte_port_sym_crypto.h', 'rte_port_eventdev.h', - 'rte_swx_port.h',) + 'rte_swx_port.h', + 'rte_swx_port_ethdev.h',) deps += ['ethdev', 'sched', 'ip_frag', 'cryptodev', 'eventdev'] if dpdk_conf.has('RTE_PORT_PCAP') diff --git a/lib/librte_port/rte_port_version.map b/lib/librte_port/rte_port_version.map index bd1fbb66b0..0d1c520357 100644 --- a/lib/librte_port/rte_port_version.map +++ b/lib/librte_port/rte_port_version.map @@ -34,8 +34,12 @@ DPDK_21 { EXPERIMENTAL { global: + # added in 19.11 rte_port_eventdev_reader_ops; - rte_port_eventdev_writer_ops; rte_port_eventdev_writer_nodrop_ops; + rte_port_eventdev_writer_ops; + # added in 20.11 + rte_swx_port_ethdev_reader_ops; + rte_swx_port_ethdev_writer_ops; }; diff --git a/lib/librte_port/rte_swx_port_ethdev.c b/lib/librte_port/rte_swx_port_ethdev.c new file mode 100644 index 0000000000..18d1c0b5db --- /dev/null +++ b/lib/librte_port/rte_swx_port_ethdev.c @@ -0,0 +1,313 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ +#include +#include +#include +#include + +#include +#include +#include + +#include "rte_swx_port_ethdev.h" + +#define CHECK(condition) \ +do { \ + if (!(condition)) \ + return NULL; \ +} while (0) + +#ifndef TRACE_LEVEL +#define TRACE_LEVEL 0 +#endif + +#if TRACE_LEVEL +#define TRACE(...) printf(__VA_ARGS__) +#else +#define TRACE(...) +#endif + +/* + * Port ETHDEV Reader + */ +struct reader { + struct { + uint16_t port_id; + uint16_t queue_id; + uint32_t burst_size; + } params; + struct rte_swx_port_in_stats stats; + struct rte_mbuf **pkts; + int n_pkts; + int pos; +}; + +static void * +reader_create(void *args) +{ + struct rte_eth_dev_info info; + struct rte_swx_port_ethdev_reader_params *params = args; + struct reader *p; + int status; + uint16_t port_id; + + /* Check input parameters. */ + CHECK(params); + + CHECK(params->dev_name); + status = rte_eth_dev_get_port_by_name(params->dev_name, &port_id); + CHECK(!status); + + status = rte_eth_dev_info_get(port_id, &info); + CHECK((status == -ENOTSUP) || (params->queue_id < info.nb_rx_queues)); + + CHECK(params->burst_size); + + /* Memory allocation. */ + p = calloc(1, sizeof(struct reader)); + CHECK(p); + + p->pkts = calloc(params->burst_size, sizeof(struct rte_mbuf *)); + if (!p->pkts) { + free(p); + CHECK(0); + } + + /* Initialization. */ + p->params.port_id = port_id; + p->params.queue_id = params->queue_id; + p->params.burst_size = params->burst_size; + + return p; +} + +static int +reader_pkt_rx(void *port, struct rte_swx_pkt *pkt) +{ + struct reader *p = port; + struct rte_mbuf *m; + + if (p->pos == p->n_pkts) { + int n_pkts; + + n_pkts = rte_eth_rx_burst(p->params.port_id, + p->params.queue_id, + p->pkts, + p->params.burst_size); + if (!n_pkts) { + p->stats.n_empty++; + return 0; + } + + TRACE("[Ethdev RX port %u queue %u] %d packets in\n", + (uint32_t)p->params.port_id, + (uint32_t)p->params.queue_id, + n_pkts); + + p->n_pkts = n_pkts; + p->pos = 0; + } + + m = p->pkts[p->pos++]; + pkt->handle = m; + pkt->pkt = m->buf_addr; + pkt->offset = m->data_off; + pkt->length = m->pkt_len; + + TRACE("[Ethdev RX port %u queue %u] Pkt %d (%u bytes at offset %u)\n", + (uint32_t)p->params.port_id, + (uint32_t)p->params.queue_id, + p->pos - 1, + pkt->length, + pkt->offset); + if (TRACE_LEVEL) + rte_hexdump(stdout, + NULL, + &((uint8_t *)m->buf_addr)[m->data_off], + m->data_len); + + p->stats.n_pkts++; + p->stats.n_bytes += pkt->length; + + return 1; +} + +static void +reader_free(void *port) +{ + struct reader *p = port; + int i; + + if (!p) + return; + + for (i = 0; i < p->n_pkts; i++) { + struct rte_mbuf *pkt = p->pkts[i]; + + rte_pktmbuf_free(pkt); + } + + free(p->pkts); + free(p); +} + +static void +reader_stats_read(void *port, struct rte_swx_port_in_stats *stats) +{ + struct reader *p = port; + + memcpy(stats, &p->stats, sizeof(p->stats)); +} + +/* + * Port ETHDEV Writer + */ +struct writer { + struct { + uint16_t port_id; + uint16_t queue_id; + uint32_t burst_size; + } params; + struct rte_swx_port_out_stats stats; + + struct rte_mbuf **pkts; + int n_pkts; +}; + +static void * +writer_create(void *args) +{ + struct rte_eth_dev_info info; + struct rte_swx_port_ethdev_writer_params *params = args; + struct writer *p; + int status; + uint16_t port_id; + + /* Check input parameters. */ + CHECK(params); + + CHECK(params->dev_name); + status = rte_eth_dev_get_port_by_name(params->dev_name, &port_id); + CHECK(!status); + + status = rte_eth_dev_info_get(port_id, &info); + CHECK((status == -ENOTSUP) || (params->queue_id < info.nb_tx_queues)); + + CHECK(params->burst_size); + + /* Memory allocation. */ + p = calloc(1, sizeof(struct writer)); + CHECK(p); + + p->pkts = calloc(params->burst_size, sizeof(struct rte_mbuf *)); + if (!p->pkts) { + free(p); + CHECK(0); + } + + /* Initialization. */ + p->params.port_id = port_id; + p->params.queue_id = params->queue_id; + p->params.burst_size = params->burst_size; + + return p; +} + +static void +__writer_flush(struct writer *p) +{ + int n_pkts; + + for (n_pkts = 0; ; ) { + n_pkts += rte_eth_tx_burst(p->params.port_id, + p->params.queue_id, + p->pkts + n_pkts, + p->n_pkts - n_pkts); + + TRACE("[Ethdev TX port %u queue %u] %d packets out\n", + (uint32_t)p->params.port_id, + (uint32_t)p->params.queue_id, + n_pkts); + + if (n_pkts == p->n_pkts) + break; + } + + p->n_pkts = 0; +} + +static void +writer_pkt_tx(void *port, struct rte_swx_pkt *pkt) +{ + struct writer *p = port; + struct rte_mbuf *m = pkt->handle; + + TRACE("[Ethdev TX port %u queue %u] Pkt %d (%u bytes at offset %u)\n", + (uint32_t)p->params.port_id, + (uint32_t)p->params.queue_id, + p->n_pkts - 1, + pkt->length, + pkt->offset); + if (TRACE_LEVEL) + rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + + m->pkt_len = pkt->length; + m->data_len = (uint16_t)pkt->length; + m->data_off = (uint16_t)pkt->offset; + + p->stats.n_pkts++; + p->stats.n_bytes += pkt->length; + + p->pkts[p->n_pkts++] = m; + if (p->n_pkts == (int)p->params.burst_size) + __writer_flush(p); +} + +static void +writer_flush(void *port) +{ + struct writer *p = port; + + if (p->n_pkts) + __writer_flush(p); +} + +static void +writer_free(void *port) +{ + struct writer *p = port; + + if (!p) + return; + + writer_flush(p); + free(p->pkts); + free(port); +} + +static void +writer_stats_read(void *port, struct rte_swx_port_out_stats *stats) +{ + struct writer *p = port; + + memcpy(stats, &p->stats, sizeof(p->stats)); +} + +/* + * Summary of port operations + */ +struct rte_swx_port_in_ops rte_swx_port_ethdev_reader_ops = { + .create = reader_create, + .free = reader_free, + .pkt_rx = reader_pkt_rx, + .stats_read = reader_stats_read, +}; + +struct rte_swx_port_out_ops rte_swx_port_ethdev_writer_ops = { + .create = writer_create, + .free = writer_free, + .pkt_tx = writer_pkt_tx, + .flush = writer_flush, + .stats_read = writer_stats_read, +}; diff --git a/lib/librte_port/rte_swx_port_ethdev.h b/lib/librte_port/rte_swx_port_ethdev.h new file mode 100644 index 0000000000..cbc2d7b213 --- /dev/null +++ b/lib/librte_port/rte_swx_port_ethdev.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ +#ifndef __INCLUDE_RTE_SWX_PORT_ETHDEV_H__ +#define __INCLUDE_RTE_SWX_PORT_ETHDEV_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * RTE SWX Ethernet Device Input and Output Ports + */ + +#include + +#include "rte_swx_port.h" + +/** Ethernet device input port (reader) creation parameters. */ +struct rte_swx_port_ethdev_reader_params { + /** Name of a valid and fully configured Ethernet device. */ + const char *dev_name; + + /** Ethernet device receive queue ID. */ + uint16_t queue_id; + + /** Ethernet device receive burst size. */ + uint32_t burst_size; +}; + +/** Ethernet device reader operations. */ +extern struct rte_swx_port_in_ops rte_swx_port_ethdev_reader_ops; + +/** Ethernet device output port (writer) creation parameters. */ +struct rte_swx_port_ethdev_writer_params { + /** Name of a valid and fully configured Ethernet device. */ + const char *dev_name; + + /** Ethernet device transmit queue ID. */ + uint16_t queue_id; + + /** Ethernet device transmit burst size. */ + uint32_t burst_size; +}; + +/** Ethernet device writer operations. */ +extern struct rte_swx_port_out_ops rte_swx_port_ethdev_writer_ops; + +#ifdef __cplusplus +} +#endif + +#endif