From e2b8dc5256c0c6d567c136401de67d3249b9086b Mon Sep 17 00:00:00 2001 From: Venkata Suresh Kumar P Date: Tue, 23 Mar 2021 14:05:03 -0400 Subject: [PATCH] port: add file descriptor SWX port Add the file descriptor input/output port type for the SWX pipeline. File descriptor port type provides interface with the kernel network stack. Example file descriptor port is TAP device. Signed-off-by: Venkata Suresh Kumar P Signed-off-by: Churchill Khangar Acked-by: Cristian Dumitrescu --- doc/api/doxy-api-index.md | 1 + examples/pipeline/cli.c | 141 +++++++++++++- examples/pipeline/obj.c | 110 +++++++++++ examples/pipeline/obj.h | 18 ++ lib/librte_port/meson.build | 2 + lib/librte_port/rte_swx_port_fd.c | 299 ++++++++++++++++++++++++++++++ lib/librte_port/rte_swx_port_fd.h | 57 ++++++ lib/librte_port/version.map | 2 + 8 files changed, 628 insertions(+), 2 deletions(-) create mode 100644 lib/librte_port/rte_swx_port_fd.c create mode 100644 lib/librte_port/rte_swx_port_fd.h diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index f4ca3e4328..f3d5d46646 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -186,6 +186,7 @@ The public API headers are grouped by topics: * SWX port: [port] (@ref rte_swx_port.h), [ethdev] (@ref rte_swx_port_ethdev.h), + [fd] (@ref rte_swx_port_fd.h), [ring] (@ref rte_swx_port_ring.h), [src/sink] (@ref rte_swx_port_source_sink.h) * SWX table: diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c index 01a2db728f..ae06658e2f 100644 --- a/examples/pipeline/cli.c +++ b/examples/pipeline/cli.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -493,6 +494,32 @@ cmd_ring(char **tokens, } } +static const char cmd_tap_help[] = +"tap \n"; + +static void +cmd_tap(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct tap *tap; + char *name; + + if (n_tokens < 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + name = tokens[1]; + + tap = tap_create(obj, name); + if (tap == NULL) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + static const char cmd_pipeline_create_help[] = "pipeline create \n"; @@ -530,7 +557,8 @@ static const char cmd_pipeline_port_in_help[] = "pipeline port in \n" " link rxq bsz \n" " ring bsz \n" -" | source \n"; +" | source \n" +" | tap mempool mtu bsz \n"; static void cmd_pipeline_port_in(char **tokens, @@ -678,6 +706,68 @@ cmd_pipeline_port_in(char **tokens, port_id, "source", ¶ms); + } else if (strcmp(tokens[t0], "tap") == 0) { + struct rte_swx_port_fd_reader_params params; + struct tap *tap; + struct mempool *mp; + + if (n_tokens < t0 + 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in tap"); + return; + } + + tap = tap_find(obj, tokens[t0 + 1]); + if (!tap) { + snprintf(out, out_size, MSG_ARG_INVALID, + "tap_name"); + return; + } + params.fd = tap->fd; + + if (strcmp(tokens[t0 + 2], "mempool") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mempool"); + return; + } + + mp = mempool_find(obj, tokens[t0 + 3]); + if (!mp) { + snprintf(out, out_size, MSG_ARG_INVALID, + "mempool_name"); + return; + } + params.mempool = mp->m; + + if (strcmp(tokens[t0 + 4], "mtu") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mtu"); + return; + } + + if (parser_read_uint32(¶ms.mtu, tokens[t0 + 5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); + return; + } + + if (strcmp(tokens[t0 + 6], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + return; + } + + if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 7])) { + snprintf(out, out_size, MSG_ARG_INVALID, + "burst_size"); + return; + } + + t0 += 8; + + status = rte_swx_pipeline_port_in_config(p->p, + port_id, + "fd", + ¶ms); + } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; @@ -698,7 +788,8 @@ static const char cmd_pipeline_port_out_help[] = "pipeline port out \n" " link txq bsz \n" " ring bsz \n" -" | sink | none\n"; +" | sink | none\n" +" | tap bsz \n"; static void cmd_pipeline_port_out(char **tokens, @@ -832,6 +923,41 @@ cmd_pipeline_port_out(char **tokens, port_id, "sink", ¶ms); + } else if (strcmp(tokens[t0], "tap") == 0) { + struct rte_swx_port_fd_writer_params params; + struct tap *tap; + + if (n_tokens < t0 + 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out tap"); + return; + } + + tap = tap_find(obj, tokens[t0 + 1]); + if (!tap) { + snprintf(out, out_size, MSG_ARG_INVALID, + "tap_name"); + return; + } + params.fd = tap->fd; + + if (strcmp(tokens[t0 + 2], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + return; + } + + if (parser_read_uint32(¶ms.burst_size, tokens[t0 + 3])) { + snprintf(out, out_size, MSG_ARG_INVALID, + "burst_size"); + return; + } + + t0 += 4; + + status = rte_swx_pipeline_port_out_config(p->p, + port_id, + "fd", + ¶ms); } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; @@ -1318,6 +1444,7 @@ cmd_help(char **tokens, "List of commands:\n" "\tmempool\n" "\tlink\n" + "\ttap\n" "\tpipeline create\n" "\tpipeline port in\n" "\tpipeline port out\n" @@ -1344,6 +1471,11 @@ cmd_help(char **tokens, return; } + if (strcmp(tokens[0], "tap") == 0) { + snprintf(out, out_size, "\n%s\n", cmd_tap_help); + return; + } + if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) { snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help); @@ -1449,6 +1581,11 @@ cli_process(char *in, char *out, size_t out_size, void *obj) return; } + if (strcmp(tokens[0], "tap") == 0) { + cmd_tap(tokens, n_tokens, out, out_size, obj); + return; + } + if (strcmp(tokens[0], "pipeline") == 0) { if ((n_tokens >= 3) && (strcmp(tokens[2], "create") == 0)) { diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c index 0e05583f87..467cda5a6d 100644 --- a/examples/pipeline/obj.c +++ b/examples/pipeline/obj.c @@ -4,11 +4,20 @@ #include #include +#include +#ifdef RTE_EXEC_ENV_LINUX +#include +#include +#endif +#include +#include +#include #include #include #include #include +#include #include #include #include @@ -33,6 +42,11 @@ TAILQ_HEAD(link_list, link); */ TAILQ_HEAD(ring_list, ring); +/* + * tap + */ +TAILQ_HEAD(tap_list, tap); + /* * pipeline */ @@ -46,6 +60,7 @@ struct obj { struct link_list link_list; struct ring_list ring_list; struct pipeline_list pipeline_list; + struct tap_list tap_list; }; /* @@ -422,6 +437,88 @@ ring_find(struct obj *obj, const char *name) return NULL; } +/* + * tap + */ +#define TAP_DEV "/dev/net/tun" + +struct tap * +tap_find(struct obj *obj, const char *name) +{ + struct tap *tap; + + if (!obj || !name) + return NULL; + + TAILQ_FOREACH(tap, &obj->tap_list, node) + if (strcmp(tap->name, name) == 0) + return tap; + + return NULL; +} + +struct tap * +tap_next(struct obj *obj, struct tap *tap) +{ + return (tap == NULL) ? + TAILQ_FIRST(&obj->tap_list) : TAILQ_NEXT(tap, node); +} + +#ifndef RTE_EXEC_ENV_LINUX + +struct tap * +tap_create(struct obj *obj __rte_unused, const char *name __rte_unused) +{ + return NULL; +} + +#else + +struct tap * +tap_create(struct obj *obj, const char *name) +{ + struct tap *tap; + struct ifreq ifr; + int fd, status; + + /* Check input params */ + if ((name == NULL) || + tap_find(obj, name)) + return NULL; + + /* Resource create */ + fd = open(TAP_DEV, O_RDWR | O_NONBLOCK); + if (fd < 0) + return NULL; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */ + strlcpy(ifr.ifr_name, name, IFNAMSIZ); + + status = ioctl(fd, TUNSETIFF, (void *) &ifr); + if (status < 0) { + close(fd); + return NULL; + } + + /* Node allocation */ + tap = calloc(1, sizeof(struct tap)); + if (tap == NULL) { + close(fd); + return NULL; + } + /* Node fill in */ + strlcpy(tap->name, name, sizeof(tap->name)); + tap->fd = fd; + + /* Node add to list */ + TAILQ_INSERT_TAIL(&obj->tap_list, tap, node); + + return tap; +} + +#endif + /* * pipeline */ @@ -484,6 +581,18 @@ pipeline_create(struct obj *obj, const char *name, int numa_node) if (status) goto error; + status = rte_swx_pipeline_port_in_type_register(p, + "fd", + &rte_swx_port_fd_reader_ops); + if (status) + goto error; + + status = rte_swx_pipeline_port_out_type_register(p, + "fd", + &rte_swx_port_fd_writer_ops); + if (status) + goto error; + status = rte_swx_pipeline_table_type_register(p, "exact", RTE_SWX_TABLE_MATCH_EXACT, @@ -549,6 +658,7 @@ obj_init(void) TAILQ_INIT(&obj->link_list); TAILQ_INIT(&obj->ring_list); TAILQ_INIT(&obj->pipeline_list); + TAILQ_INIT(&obj->tap_list); return obj; } diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h index 1aab2a37b8..b921610554 100644 --- a/examples/pipeline/obj.h +++ b/examples/pipeline/obj.h @@ -125,6 +125,24 @@ ring_create(struct obj *obj, struct ring * ring_find(struct obj *obj, const char *name); +/* + * tap + */ +struct tap { + TAILQ_ENTRY(tap) node; + char name[NAME_SIZE]; + int fd; +}; + +struct tap * +tap_find(struct obj *obj, const char *name); + +struct tap * +tap_next(struct obj *obj, struct tap *tap); + +struct tap * +tap_create(struct obj *obj, const char *name); + /* * pipeline */ diff --git a/lib/librte_port/meson.build b/lib/librte_port/meson.build index 9fcd62cd80..435b64a131 100644 --- a/lib/librte_port/meson.build +++ b/lib/librte_port/meson.build @@ -12,6 +12,7 @@ sources = files( 'rte_port_sym_crypto.c', 'rte_port_eventdev.c', 'rte_swx_port_ethdev.c', + 'rte_swx_port_fd.c', 'rte_swx_port_ring.c', 'rte_swx_port_source_sink.c', ) @@ -28,6 +29,7 @@ headers = files( 'rte_port_eventdev.h', 'rte_swx_port.h', 'rte_swx_port_ethdev.h', + 'rte_swx_port_fd.h', 'rte_swx_port_ring.h', 'rte_swx_port_source_sink.h', ) diff --git a/lib/librte_port/rte_swx_port_fd.c b/lib/librte_port/rte_swx_port_fd.c new file mode 100644 index 0000000000..aa7315a15a --- /dev/null +++ b/lib/librte_port/rte_swx_port_fd.c @@ -0,0 +1,299 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ +#include +#include +#include + +#include +#include +#include + +#include "rte_swx_port_fd.h" + +#ifndef TRACE_LEVEL +#define TRACE_LEVEL 0 +#endif + +#if TRACE_LEVEL +#define TRACE(...) printf(__VA_ARGS__) +#else +#define TRACE(...) +#endif + +/* + * FD Reader + */ +struct reader { + struct { + int fd; + uint32_t mtu; + uint32_t burst_size; + struct rte_mempool *mempool; + } params; + + struct rte_swx_port_in_stats stats; + struct rte_mbuf **pkts; + uint32_t n_pkts; + uint32_t pos; +}; + +static void * +reader_create(void *args) +{ + struct rte_swx_port_fd_reader_params *conf = args; + struct reader *p; + + /* Check input parameters. */ + if (!conf || conf->fd < 0 || conf->mtu == 0 || !conf->mempool) + return NULL; + + /* Memory allocation. */ + p = calloc(1, sizeof(struct reader)); + if (!p) + return NULL; + + p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *)); + if (!p->pkts) { + free(p); + return NULL; + } + + /* Initialization. */ + p->params.fd = conf->fd; + p->params.mtu = conf->mtu; + p->params.burst_size = conf->burst_size; + p->params.mempool = conf->mempool; + + return p; +} + +static void +reader_free(void *port) +{ + struct reader *p = port; + uint32_t i; + + if (!p) + return; + + for (i = 0; i < p->n_pkts; i++) + rte_pktmbuf_free(p->pkts[i]); + + free(p->pkts); + free(p); +} + +static int +reader_pkt_rx(void *port, struct rte_swx_pkt *pkt) +{ + struct reader *p = port; + struct rte_mbuf *m; + void *pkt_data; + ssize_t n_bytes; + uint32_t i, j; + + if (p->n_pkts == p->pos) { + if (rte_pktmbuf_alloc_bulk(p->params.mempool, p->pkts, p->params.burst_size) != 0) + return 0; + + for (i = 0; i < p->params.burst_size; i++) { + m = p->pkts[i]; + pkt_data = rte_pktmbuf_mtod(m, void *); + n_bytes = read(p->params.fd, pkt_data, (size_t) p->params.mtu); + + if (n_bytes <= 0) + break; + + m->data_len = n_bytes; + m->pkt_len = n_bytes; + + p->stats.n_pkts++; + p->stats.n_bytes += n_bytes; + } + + for (j = i; j < p->params.burst_size; j++) + rte_pktmbuf_free(p->pkts[j]); + + p->n_pkts = i; + p->pos = 0; + + if (!p->n_pkts) + return 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("[FD %u] Pkt %d (%u bytes at offset %u)\n", + (uint32_t)p->params.fd, + 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); + + return 1; +} + +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)); +} + +/* + * FD Writer + */ +struct writer { + struct { + int fd; + uint32_t mtu; + uint32_t burst_size; + struct rte_mempool *mempool; + } params; + + struct rte_swx_port_out_stats stats; + struct rte_mbuf **pkts; + uint32_t n_pkts; +}; + +static void * +writer_create(void *args) +{ + struct rte_swx_port_fd_writer_params *conf = args; + struct writer *p; + + /* Check input parameters. */ + if (!conf) + return NULL; + + /* Memory allocation. */ + p = calloc(1, sizeof(struct writer)); + if (!p) + return NULL; + + + p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *)); + if (!p->pkts) { + free(p); + return NULL; + } + + /* Initialization. */ + p->params.fd = conf->fd; + p->params.burst_size = conf->burst_size; + + return p; +} + +static void +__writer_flush(struct writer *p) +{ + struct rte_mbuf *pkt; + void *pkt_data; + size_t n_bytes; + ssize_t ret; + uint32_t i; + + for (i = 0; i < p->n_pkts; i++) { + pkt = p->pkts[i]; + pkt_data = rte_pktmbuf_mtod(pkt, void*); + n_bytes = rte_pktmbuf_data_len(pkt); + + ret = write(p->params.fd, pkt_data, n_bytes); + if (ret < 0) + break; + } + + TRACE("[FD %u] %u packets out\n", + (uint32_t)p->params.fd, + p->n_pkts); + + for (i = 0; i < p->n_pkts; i++) + rte_pktmbuf_free(p->pkts[i]); + + 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("[FD %u] Pkt %u (%u bytes at offset %u)\n", + (uint32_t)p->params.fd, + 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 == 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(p); +} + +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_fd_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_fd_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_fd.h b/lib/librte_port/rte_swx_port_fd.h new file mode 100644 index 0000000000..ecf3349f5f --- /dev/null +++ b/lib/librte_port/rte_swx_port_fd.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#ifndef __INCLUDE_RTE_SWX_PORT_FD_H__ +#define __INCLUDE_RTE_SWX_PORT_FD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * RTE SWX FD Input and Output Ports + * + ***/ +#include + +#include + +#include "rte_swx_port.h" + +/** fd_reader port parameters */ +struct rte_swx_port_fd_reader_params { + /** File descriptor. Must be valid and opened in non-blocking mode. */ + int fd; + + /** Maximum Transfer Unit (MTU) */ + uint32_t mtu; + + /** Pre-initialized buffer pool */ + struct rte_mempool *mempool; + + /** RX burst size */ + uint32_t burst_size; +}; + +/** fd_reader port operations */ +extern struct rte_swx_port_in_ops rte_swx_port_fd_reader_ops; + +/** fd_writer port parameters */ +struct rte_swx_port_fd_writer_params { + /** File descriptor. Must be valid and opened in non-blocking mode. */ + int fd; + + /** TX burst size */ + uint32_t burst_size; +}; + +/** fd_writer port operations */ +extern struct rte_swx_port_out_ops rte_swx_port_fd_writer_ops; + +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_RTE_SWX_PORT_FD_H__ */ diff --git a/lib/librte_port/version.map b/lib/librte_port/version.map index e6f35e6559..70922e11ee 100644 --- a/lib/librte_port/version.map +++ b/lib/librte_port/version.map @@ -46,6 +46,8 @@ EXPERIMENTAL { rte_swx_port_source_ops; # added in 21.05 + rte_swx_port_fd_reader_ops; + rte_swx_port_fd_writer_ops; rte_swx_port_ring_reader_ops; rte_swx_port_ring_writer_ops; }; -- 2.20.1