b94eb6cd35
Add packet clone operation to the output ports in order to support packet mirroring. Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com> Signed-off-by: Kamalakannan R <kamalakannan.r@intel.com>
362 lines
6.7 KiB
C
362 lines
6.7 KiB
C
/* 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_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->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
|
|
m->pkt_len = 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_pkt_fast_clone_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) (fast clone)\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->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
|
|
m->pkt_len = pkt->length;
|
|
m->data_off = (uint16_t)pkt->offset;
|
|
rte_pktmbuf_refcnt_update(m, 1);
|
|
|
|
p->stats.n_pkts++;
|
|
p->stats.n_bytes += pkt->length;
|
|
p->stats.n_pkts_clone++;
|
|
|
|
p->pkts[p->n_pkts++] = m;
|
|
if (p->n_pkts == p->params.burst_size)
|
|
__writer_flush(p);
|
|
}
|
|
|
|
static void
|
|
writer_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length)
|
|
{
|
|
struct writer *p = port;
|
|
struct rte_mbuf *m = pkt->handle, *m_clone;
|
|
|
|
TRACE("[FD %u] Pkt %u (%u bytes at offset %u) (clone)\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->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
|
|
m->pkt_len = pkt->length;
|
|
m->data_off = (uint16_t)pkt->offset;
|
|
|
|
m_clone = rte_pktmbuf_copy(m, m->pool, 0, truncation_length);
|
|
if (!m_clone) {
|
|
p->stats.n_pkts_clone_err++;
|
|
return;
|
|
}
|
|
|
|
p->stats.n_pkts++;
|
|
p->stats.n_bytes += pkt->length;
|
|
p->stats.n_pkts_clone++;
|
|
|
|
p->pkts[p->n_pkts++] = m_clone;
|
|
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,
|
|
.pkt_fast_clone_tx = writer_pkt_fast_clone_tx,
|
|
.pkt_clone_tx = writer_pkt_clone_tx,
|
|
.flush = writer_flush,
|
|
.stats_read = writer_stats_read,
|
|
};
|