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 <venkata.suresh.kumar.p@intel.com>
Signed-off-by: Churchill Khangar <churchill.khangar@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
This commit is contained in:
Venkata Suresh Kumar P 2021-03-23 14:05:03 -04:00 committed by Thomas Monjalon
parent 66440b7b22
commit e2b8dc5256
8 changed files with 628 additions and 2 deletions

View File

@ -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:

View File

@ -12,6 +12,7 @@
#include <rte_swx_port_ethdev.h>
#include <rte_swx_port_ring.h>
#include <rte_swx_port_source_sink.h>
#include <rte_swx_port_fd.h>
#include <rte_swx_pipeline.h>
#include <rte_swx_ctl.h>
@ -493,6 +494,32 @@ cmd_ring(char **tokens,
}
}
static const char cmd_tap_help[] =
"tap <tap_name>\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 <pipeline_name> create <numa_node>\n";
@ -530,7 +557,8 @@ static const char cmd_pipeline_port_in_help[] =
"pipeline <pipeline_name> port in <port_id>\n"
" link <link_name> rxq <queue_id> bsz <burst_size>\n"
" ring <ring_name> bsz <burst_size>\n"
" | source <mempool_name> <file_name>\n";
" | source <mempool_name> <file_name>\n"
" | tap <tap_name> mempool <mempool_name> mtu <mtu> bsz <burst_size>\n";
static void
cmd_pipeline_port_in(char **tokens,
@ -678,6 +706,68 @@ cmd_pipeline_port_in(char **tokens,
port_id,
"source",
&params);
} 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(&params.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(&params.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",
&params);
} else {
snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
return;
@ -698,7 +788,8 @@ static const char cmd_pipeline_port_out_help[] =
"pipeline <pipeline_name> port out <port_id>\n"
" link <link_name> txq <txq_id> bsz <burst_size>\n"
" ring <ring_name> bsz <burst_size>\n"
" | sink <file_name> | none\n";
" | sink <file_name> | none\n"
" | tap <tap_name> bsz <burst_size>\n";
static void
cmd_pipeline_port_out(char **tokens,
@ -832,6 +923,41 @@ cmd_pipeline_port_out(char **tokens,
port_id,
"sink",
&params);
} 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(&params.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",
&params);
} 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)) {

View File

@ -4,11 +4,20 @@
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#ifdef RTE_EXEC_ENV_LINUX
#include <linux/if.h>
#include <linux/if_tun.h>
#endif
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include <rte_ethdev.h>
#include <rte_swx_port_ethdev.h>
#include <rte_swx_port_fd.h>
#include <rte_swx_port_ring.h>
#include <rte_swx_port_source_sink.h>
#include <rte_swx_table_em.h>
@ -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;
}

View File

@ -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
*/

View File

@ -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',
)

View File

@ -0,0 +1,299 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2021 Intel Corporation
*/
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <rte_mbuf.h>
#include <rte_malloc.h>
#include <rte_hexdump.h>
#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,
};

View File

@ -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 <stdint.h>
#include <rte_mempool.h>
#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__ */

View File

@ -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;
};