199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2021 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson #include <string.h>
599a2dd95SBruce Richardson #include <stdint.h>
6*72b452c5SDmitry Kozlyuk #include <stdlib.h>
799a2dd95SBruce Richardson #include <unistd.h>
899a2dd95SBruce Richardson
999a2dd95SBruce Richardson #include <rte_mbuf.h>
1099a2dd95SBruce Richardson #include <rte_hexdump.h>
1199a2dd95SBruce Richardson
1299a2dd95SBruce Richardson #include "rte_swx_port_fd.h"
1399a2dd95SBruce Richardson
1499a2dd95SBruce Richardson #ifndef TRACE_LEVEL
1599a2dd95SBruce Richardson #define TRACE_LEVEL 0
1699a2dd95SBruce Richardson #endif
1799a2dd95SBruce Richardson
1899a2dd95SBruce Richardson #if TRACE_LEVEL
1999a2dd95SBruce Richardson #define TRACE(...) printf(__VA_ARGS__)
2099a2dd95SBruce Richardson #else
2199a2dd95SBruce Richardson #define TRACE(...)
2299a2dd95SBruce Richardson #endif
2399a2dd95SBruce Richardson
2499a2dd95SBruce Richardson /*
2599a2dd95SBruce Richardson * FD Reader
2699a2dd95SBruce Richardson */
2799a2dd95SBruce Richardson struct reader {
2899a2dd95SBruce Richardson struct {
2999a2dd95SBruce Richardson int fd;
3099a2dd95SBruce Richardson uint32_t mtu;
3199a2dd95SBruce Richardson uint32_t burst_size;
3299a2dd95SBruce Richardson struct rte_mempool *mempool;
3399a2dd95SBruce Richardson } params;
3499a2dd95SBruce Richardson
3599a2dd95SBruce Richardson struct rte_swx_port_in_stats stats;
3699a2dd95SBruce Richardson struct rte_mbuf **pkts;
3799a2dd95SBruce Richardson uint32_t n_pkts;
3899a2dd95SBruce Richardson uint32_t pos;
3999a2dd95SBruce Richardson };
4099a2dd95SBruce Richardson
4199a2dd95SBruce Richardson static void *
reader_create(void * args)4299a2dd95SBruce Richardson reader_create(void *args)
4399a2dd95SBruce Richardson {
4499a2dd95SBruce Richardson struct rte_swx_port_fd_reader_params *conf = args;
4599a2dd95SBruce Richardson struct reader *p;
4699a2dd95SBruce Richardson
4799a2dd95SBruce Richardson /* Check input parameters. */
4899a2dd95SBruce Richardson if (!conf || conf->fd < 0 || conf->mtu == 0 || !conf->mempool)
4999a2dd95SBruce Richardson return NULL;
5099a2dd95SBruce Richardson
5199a2dd95SBruce Richardson /* Memory allocation. */
5299a2dd95SBruce Richardson p = calloc(1, sizeof(struct reader));
5399a2dd95SBruce Richardson if (!p)
5499a2dd95SBruce Richardson return NULL;
5599a2dd95SBruce Richardson
5699a2dd95SBruce Richardson p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *));
5799a2dd95SBruce Richardson if (!p->pkts) {
5899a2dd95SBruce Richardson free(p);
5999a2dd95SBruce Richardson return NULL;
6099a2dd95SBruce Richardson }
6199a2dd95SBruce Richardson
6299a2dd95SBruce Richardson /* Initialization. */
6399a2dd95SBruce Richardson p->params.fd = conf->fd;
6499a2dd95SBruce Richardson p->params.mtu = conf->mtu;
6599a2dd95SBruce Richardson p->params.burst_size = conf->burst_size;
6699a2dd95SBruce Richardson p->params.mempool = conf->mempool;
6799a2dd95SBruce Richardson
6899a2dd95SBruce Richardson return p;
6999a2dd95SBruce Richardson }
7099a2dd95SBruce Richardson
7199a2dd95SBruce Richardson static void
reader_free(void * port)7299a2dd95SBruce Richardson reader_free(void *port)
7399a2dd95SBruce Richardson {
7499a2dd95SBruce Richardson struct reader *p = port;
7599a2dd95SBruce Richardson uint32_t i;
7699a2dd95SBruce Richardson
7799a2dd95SBruce Richardson if (!p)
7899a2dd95SBruce Richardson return;
7999a2dd95SBruce Richardson
8099a2dd95SBruce Richardson for (i = 0; i < p->n_pkts; i++)
8199a2dd95SBruce Richardson rte_pktmbuf_free(p->pkts[i]);
8299a2dd95SBruce Richardson
8399a2dd95SBruce Richardson free(p->pkts);
8499a2dd95SBruce Richardson free(p);
8599a2dd95SBruce Richardson }
8699a2dd95SBruce Richardson
8799a2dd95SBruce Richardson static int
reader_pkt_rx(void * port,struct rte_swx_pkt * pkt)8899a2dd95SBruce Richardson reader_pkt_rx(void *port, struct rte_swx_pkt *pkt)
8999a2dd95SBruce Richardson {
9099a2dd95SBruce Richardson struct reader *p = port;
9199a2dd95SBruce Richardson struct rte_mbuf *m;
9299a2dd95SBruce Richardson void *pkt_data;
9399a2dd95SBruce Richardson ssize_t n_bytes;
9499a2dd95SBruce Richardson uint32_t i, j;
9599a2dd95SBruce Richardson
9699a2dd95SBruce Richardson if (p->n_pkts == p->pos) {
9799a2dd95SBruce Richardson if (rte_pktmbuf_alloc_bulk(p->params.mempool, p->pkts, p->params.burst_size) != 0)
9899a2dd95SBruce Richardson return 0;
9999a2dd95SBruce Richardson
10099a2dd95SBruce Richardson for (i = 0; i < p->params.burst_size; i++) {
10199a2dd95SBruce Richardson m = p->pkts[i];
10299a2dd95SBruce Richardson pkt_data = rte_pktmbuf_mtod(m, void *);
10399a2dd95SBruce Richardson n_bytes = read(p->params.fd, pkt_data, (size_t) p->params.mtu);
10499a2dd95SBruce Richardson
10599a2dd95SBruce Richardson if (n_bytes <= 0)
10699a2dd95SBruce Richardson break;
10799a2dd95SBruce Richardson
10899a2dd95SBruce Richardson m->data_len = n_bytes;
10999a2dd95SBruce Richardson m->pkt_len = n_bytes;
11099a2dd95SBruce Richardson
11199a2dd95SBruce Richardson p->stats.n_pkts++;
11299a2dd95SBruce Richardson p->stats.n_bytes += n_bytes;
11399a2dd95SBruce Richardson }
11499a2dd95SBruce Richardson
11599a2dd95SBruce Richardson for (j = i; j < p->params.burst_size; j++)
11699a2dd95SBruce Richardson rte_pktmbuf_free(p->pkts[j]);
11799a2dd95SBruce Richardson
11899a2dd95SBruce Richardson p->n_pkts = i;
11999a2dd95SBruce Richardson p->pos = 0;
12099a2dd95SBruce Richardson
12199a2dd95SBruce Richardson if (!p->n_pkts)
12299a2dd95SBruce Richardson return 0;
12399a2dd95SBruce Richardson }
12499a2dd95SBruce Richardson
12599a2dd95SBruce Richardson m = p->pkts[p->pos++];
12699a2dd95SBruce Richardson pkt->handle = m;
12799a2dd95SBruce Richardson pkt->pkt = m->buf_addr;
12899a2dd95SBruce Richardson pkt->offset = m->data_off;
12999a2dd95SBruce Richardson pkt->length = m->pkt_len;
13099a2dd95SBruce Richardson
13199a2dd95SBruce Richardson TRACE("[FD %u] Pkt %d (%u bytes at offset %u)\n",
13299a2dd95SBruce Richardson (uint32_t)p->params.fd,
13399a2dd95SBruce Richardson p->pos - 1,
13499a2dd95SBruce Richardson pkt->length,
13599a2dd95SBruce Richardson pkt->offset);
13699a2dd95SBruce Richardson
13799a2dd95SBruce Richardson if (TRACE_LEVEL)
13899a2dd95SBruce Richardson rte_hexdump(stdout, NULL,
13999a2dd95SBruce Richardson &((uint8_t *)m->buf_addr)[m->data_off], m->data_len);
14099a2dd95SBruce Richardson
14199a2dd95SBruce Richardson return 1;
14299a2dd95SBruce Richardson }
14399a2dd95SBruce Richardson
14499a2dd95SBruce Richardson static void
reader_stats_read(void * port,struct rte_swx_port_in_stats * stats)14599a2dd95SBruce Richardson reader_stats_read(void *port, struct rte_swx_port_in_stats *stats)
14699a2dd95SBruce Richardson {
14799a2dd95SBruce Richardson struct reader *p = port;
14899a2dd95SBruce Richardson
14999a2dd95SBruce Richardson memcpy(stats, &p->stats, sizeof(p->stats));
15099a2dd95SBruce Richardson }
15199a2dd95SBruce Richardson
15299a2dd95SBruce Richardson /*
15399a2dd95SBruce Richardson * FD Writer
15499a2dd95SBruce Richardson */
15599a2dd95SBruce Richardson struct writer {
15699a2dd95SBruce Richardson struct {
15799a2dd95SBruce Richardson int fd;
15899a2dd95SBruce Richardson uint32_t mtu;
15999a2dd95SBruce Richardson uint32_t burst_size;
16099a2dd95SBruce Richardson struct rte_mempool *mempool;
16199a2dd95SBruce Richardson } params;
16299a2dd95SBruce Richardson
16399a2dd95SBruce Richardson struct rte_swx_port_out_stats stats;
16499a2dd95SBruce Richardson struct rte_mbuf **pkts;
16599a2dd95SBruce Richardson uint32_t n_pkts;
16699a2dd95SBruce Richardson };
16799a2dd95SBruce Richardson
16899a2dd95SBruce Richardson static void *
writer_create(void * args)16999a2dd95SBruce Richardson writer_create(void *args)
17099a2dd95SBruce Richardson {
17199a2dd95SBruce Richardson struct rte_swx_port_fd_writer_params *conf = args;
17299a2dd95SBruce Richardson struct writer *p;
17399a2dd95SBruce Richardson
17499a2dd95SBruce Richardson /* Check input parameters. */
17599a2dd95SBruce Richardson if (!conf)
17699a2dd95SBruce Richardson return NULL;
17799a2dd95SBruce Richardson
17899a2dd95SBruce Richardson /* Memory allocation. */
17999a2dd95SBruce Richardson p = calloc(1, sizeof(struct writer));
18099a2dd95SBruce Richardson if (!p)
18199a2dd95SBruce Richardson return NULL;
18299a2dd95SBruce Richardson
18399a2dd95SBruce Richardson
18499a2dd95SBruce Richardson p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *));
18599a2dd95SBruce Richardson if (!p->pkts) {
18699a2dd95SBruce Richardson free(p);
18799a2dd95SBruce Richardson return NULL;
18899a2dd95SBruce Richardson }
18999a2dd95SBruce Richardson
19099a2dd95SBruce Richardson /* Initialization. */
19199a2dd95SBruce Richardson p->params.fd = conf->fd;
19299a2dd95SBruce Richardson p->params.burst_size = conf->burst_size;
19399a2dd95SBruce Richardson
19499a2dd95SBruce Richardson return p;
19599a2dd95SBruce Richardson }
19699a2dd95SBruce Richardson
19799a2dd95SBruce Richardson static void
__writer_flush(struct writer * p)19899a2dd95SBruce Richardson __writer_flush(struct writer *p)
19999a2dd95SBruce Richardson {
20099a2dd95SBruce Richardson struct rte_mbuf *pkt;
20199a2dd95SBruce Richardson void *pkt_data;
20299a2dd95SBruce Richardson size_t n_bytes;
20399a2dd95SBruce Richardson ssize_t ret;
20499a2dd95SBruce Richardson uint32_t i;
20599a2dd95SBruce Richardson
20699a2dd95SBruce Richardson for (i = 0; i < p->n_pkts; i++) {
20799a2dd95SBruce Richardson pkt = p->pkts[i];
20899a2dd95SBruce Richardson pkt_data = rte_pktmbuf_mtod(pkt, void*);
20999a2dd95SBruce Richardson n_bytes = rte_pktmbuf_data_len(pkt);
21099a2dd95SBruce Richardson
21199a2dd95SBruce Richardson ret = write(p->params.fd, pkt_data, n_bytes);
21299a2dd95SBruce Richardson if (ret < 0)
21399a2dd95SBruce Richardson break;
21499a2dd95SBruce Richardson }
21599a2dd95SBruce Richardson
21699a2dd95SBruce Richardson TRACE("[FD %u] %u packets out\n",
21799a2dd95SBruce Richardson (uint32_t)p->params.fd,
21899a2dd95SBruce Richardson p->n_pkts);
21999a2dd95SBruce Richardson
22099a2dd95SBruce Richardson for (i = 0; i < p->n_pkts; i++)
22199a2dd95SBruce Richardson rte_pktmbuf_free(p->pkts[i]);
22299a2dd95SBruce Richardson
22399a2dd95SBruce Richardson p->n_pkts = 0;
22499a2dd95SBruce Richardson }
22599a2dd95SBruce Richardson
22699a2dd95SBruce Richardson static void
writer_pkt_tx(void * port,struct rte_swx_pkt * pkt)22799a2dd95SBruce Richardson writer_pkt_tx(void *port, struct rte_swx_pkt *pkt)
22899a2dd95SBruce Richardson {
22999a2dd95SBruce Richardson struct writer *p = port;
23099a2dd95SBruce Richardson struct rte_mbuf *m = pkt->handle;
23199a2dd95SBruce Richardson
23299a2dd95SBruce Richardson TRACE("[FD %u] Pkt %u (%u bytes at offset %u)\n",
23399a2dd95SBruce Richardson (uint32_t)p->params.fd,
23499a2dd95SBruce Richardson p->n_pkts - 1,
23599a2dd95SBruce Richardson pkt->length,
23699a2dd95SBruce Richardson pkt->offset);
23799a2dd95SBruce Richardson
23899a2dd95SBruce Richardson if (TRACE_LEVEL)
23999a2dd95SBruce Richardson rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
24099a2dd95SBruce Richardson
241b94eb6cdSCristian Dumitrescu m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
24299a2dd95SBruce Richardson m->pkt_len = pkt->length;
24399a2dd95SBruce Richardson m->data_off = (uint16_t)pkt->offset;
24499a2dd95SBruce Richardson
24599a2dd95SBruce Richardson p->stats.n_pkts++;
24699a2dd95SBruce Richardson p->stats.n_bytes += pkt->length;
24799a2dd95SBruce Richardson
24899a2dd95SBruce Richardson p->pkts[p->n_pkts++] = m;
24999a2dd95SBruce Richardson if (p->n_pkts == p->params.burst_size)
25099a2dd95SBruce Richardson __writer_flush(p);
25199a2dd95SBruce Richardson }
25299a2dd95SBruce Richardson
25399a2dd95SBruce Richardson static void
writer_pkt_fast_clone_tx(void * port,struct rte_swx_pkt * pkt)254b94eb6cdSCristian Dumitrescu writer_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt)
255b94eb6cdSCristian Dumitrescu {
256b94eb6cdSCristian Dumitrescu struct writer *p = port;
257b94eb6cdSCristian Dumitrescu struct rte_mbuf *m = pkt->handle;
258b94eb6cdSCristian Dumitrescu
259b94eb6cdSCristian Dumitrescu TRACE("[FD %u] Pkt %u (%u bytes at offset %u) (fast clone)\n",
260b94eb6cdSCristian Dumitrescu (uint32_t)p->params.fd,
261b94eb6cdSCristian Dumitrescu p->n_pkts - 1,
262b94eb6cdSCristian Dumitrescu pkt->length,
263b94eb6cdSCristian Dumitrescu pkt->offset);
264b94eb6cdSCristian Dumitrescu if (TRACE_LEVEL)
265b94eb6cdSCristian Dumitrescu rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
266b94eb6cdSCristian Dumitrescu
267b94eb6cdSCristian Dumitrescu m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
268b94eb6cdSCristian Dumitrescu m->pkt_len = pkt->length;
269b94eb6cdSCristian Dumitrescu m->data_off = (uint16_t)pkt->offset;
270b94eb6cdSCristian Dumitrescu rte_pktmbuf_refcnt_update(m, 1);
271b94eb6cdSCristian Dumitrescu
272b94eb6cdSCristian Dumitrescu p->stats.n_pkts++;
273b94eb6cdSCristian Dumitrescu p->stats.n_bytes += pkt->length;
274b94eb6cdSCristian Dumitrescu p->stats.n_pkts_clone++;
275b94eb6cdSCristian Dumitrescu
276b94eb6cdSCristian Dumitrescu p->pkts[p->n_pkts++] = m;
277b94eb6cdSCristian Dumitrescu if (p->n_pkts == p->params.burst_size)
278b94eb6cdSCristian Dumitrescu __writer_flush(p);
279b94eb6cdSCristian Dumitrescu }
280b94eb6cdSCristian Dumitrescu
281b94eb6cdSCristian Dumitrescu static void
writer_pkt_clone_tx(void * port,struct rte_swx_pkt * pkt,uint32_t truncation_length)282b94eb6cdSCristian Dumitrescu writer_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length)
283b94eb6cdSCristian Dumitrescu {
284b94eb6cdSCristian Dumitrescu struct writer *p = port;
285b94eb6cdSCristian Dumitrescu struct rte_mbuf *m = pkt->handle, *m_clone;
286b94eb6cdSCristian Dumitrescu
287b94eb6cdSCristian Dumitrescu TRACE("[FD %u] Pkt %u (%u bytes at offset %u) (clone)\n",
288b94eb6cdSCristian Dumitrescu (uint32_t)p->params.fd,
289b94eb6cdSCristian Dumitrescu p->n_pkts - 1,
290b94eb6cdSCristian Dumitrescu pkt->length,
291b94eb6cdSCristian Dumitrescu pkt->offset);
292b94eb6cdSCristian Dumitrescu if (TRACE_LEVEL)
293b94eb6cdSCristian Dumitrescu rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
294b94eb6cdSCristian Dumitrescu
295b94eb6cdSCristian Dumitrescu m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
296b94eb6cdSCristian Dumitrescu m->pkt_len = pkt->length;
297b94eb6cdSCristian Dumitrescu m->data_off = (uint16_t)pkt->offset;
298b94eb6cdSCristian Dumitrescu
299b94eb6cdSCristian Dumitrescu m_clone = rte_pktmbuf_copy(m, m->pool, 0, truncation_length);
300b94eb6cdSCristian Dumitrescu if (!m_clone) {
301b94eb6cdSCristian Dumitrescu p->stats.n_pkts_clone_err++;
302b94eb6cdSCristian Dumitrescu return;
303b94eb6cdSCristian Dumitrescu }
304b94eb6cdSCristian Dumitrescu
305b94eb6cdSCristian Dumitrescu p->stats.n_pkts++;
306b94eb6cdSCristian Dumitrescu p->stats.n_bytes += pkt->length;
307b94eb6cdSCristian Dumitrescu p->stats.n_pkts_clone++;
308b94eb6cdSCristian Dumitrescu
309b94eb6cdSCristian Dumitrescu p->pkts[p->n_pkts++] = m_clone;
310b94eb6cdSCristian Dumitrescu if (p->n_pkts == p->params.burst_size)
311b94eb6cdSCristian Dumitrescu __writer_flush(p);
312b94eb6cdSCristian Dumitrescu }
313b94eb6cdSCristian Dumitrescu
314b94eb6cdSCristian Dumitrescu static void
writer_flush(void * port)31599a2dd95SBruce Richardson writer_flush(void *port)
31699a2dd95SBruce Richardson {
31799a2dd95SBruce Richardson struct writer *p = port;
31899a2dd95SBruce Richardson
31999a2dd95SBruce Richardson if (p->n_pkts)
32099a2dd95SBruce Richardson __writer_flush(p);
32199a2dd95SBruce Richardson }
32299a2dd95SBruce Richardson
32399a2dd95SBruce Richardson static void
writer_free(void * port)32499a2dd95SBruce Richardson writer_free(void *port)
32599a2dd95SBruce Richardson {
32699a2dd95SBruce Richardson struct writer *p = port;
32799a2dd95SBruce Richardson
32899a2dd95SBruce Richardson if (!p)
32999a2dd95SBruce Richardson return;
33099a2dd95SBruce Richardson
33199a2dd95SBruce Richardson writer_flush(p);
33299a2dd95SBruce Richardson free(p->pkts);
33399a2dd95SBruce Richardson free(p);
33499a2dd95SBruce Richardson }
33599a2dd95SBruce Richardson
33699a2dd95SBruce Richardson static void
writer_stats_read(void * port,struct rte_swx_port_out_stats * stats)33799a2dd95SBruce Richardson writer_stats_read(void *port, struct rte_swx_port_out_stats *stats)
33899a2dd95SBruce Richardson {
33999a2dd95SBruce Richardson struct writer *p = port;
34099a2dd95SBruce Richardson
34199a2dd95SBruce Richardson memcpy(stats, &p->stats, sizeof(p->stats));
34299a2dd95SBruce Richardson }
34399a2dd95SBruce Richardson
34499a2dd95SBruce Richardson /*
34599a2dd95SBruce Richardson * Summary of port operations
34699a2dd95SBruce Richardson */
34799a2dd95SBruce Richardson struct rte_swx_port_in_ops rte_swx_port_fd_reader_ops = {
34899a2dd95SBruce Richardson .create = reader_create,
34999a2dd95SBruce Richardson .free = reader_free,
35099a2dd95SBruce Richardson .pkt_rx = reader_pkt_rx,
35199a2dd95SBruce Richardson .stats_read = reader_stats_read,
35299a2dd95SBruce Richardson };
35399a2dd95SBruce Richardson
35499a2dd95SBruce Richardson struct rte_swx_port_out_ops rte_swx_port_fd_writer_ops = {
35599a2dd95SBruce Richardson .create = writer_create,
35699a2dd95SBruce Richardson .free = writer_free,
35799a2dd95SBruce Richardson .pkt_tx = writer_pkt_tx,
358b94eb6cdSCristian Dumitrescu .pkt_fast_clone_tx = writer_pkt_fast_clone_tx,
359b94eb6cdSCristian Dumitrescu .pkt_clone_tx = writer_pkt_clone_tx,
36099a2dd95SBruce Richardson .flush = writer_flush,
36199a2dd95SBruce Richardson .stats_read = writer_stats_read,
36299a2dd95SBruce Richardson };
363