#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "main.h"
static struct fwd_info fwd_info;
static struct fwd_info *fwd = &fwd_info;
struct create_txbuff_thd_priv_t {
pkt_api_t pkt_api;
};
#define foreach_thd_lport(_t, _lp) \
for (int _i = 0; _i < _t->lport_cnt && (_lp = _t->lports[_i]); _i++, _lp = _t->lports[_i])
#define TIMEOUT_VALUE 1000
enum thread_quit_state {
THD_RUN = 0,
THD_QUIT,
THD_DONE,
};
__rx_burst(pkt_api_t api,
struct fwd_port *pd,
pktmbuf_t **mbufs,
int n_pkts)
{
switch (api) {
case XSKDEV_PKT_API:
case PKTDEV_PKT_API:
default:
break;
}
return 0;
}
__tx_burst(pkt_api_t api,
struct fwd_port *pd,
pktmbuf_t **mbufs,
int n_pkts)
{
switch (api) {
case XSKDEV_PKT_API:
case PKTDEV_PKT_API:
default:
break;
}
return 0;
}
__tx_flush(
struct fwd_port *pd, pkt_api_t api,
pktmbuf_t **mbufs, uint16_t n_pkts)
{
while (n_pkts > 0) {
uint16_t n = __tx_burst(api, pd, mbufs, n_pkts);
if (n == PKTDEV_ADMIN_STATE_DOWN)
return n;
n_pkts -= n;
mbufs += n;
}
return n_pkts;
}
static int
{
struct fwd_port *pd = lport->priv_;
int n_pkts;
if (!pd)
CNE_ERR_RET(
"fwd_port passed in lport private data is NULL\n");
n_pkts = __rx_burst(fwd->pkt_api, pd, pd->rx_mbufs, fwd->burst);
if (n_pkts == PKTDEV_ADMIN_STATE_DOWN)
return -1;
if (n_pkts)
return 0;
}
static int
{
struct fwd_port *pd = lport->priv_;
struct create_txbuff_thd_priv_t *thd_private = pd->thd->priv_;
int i, n_pkts;
if (!pd)
CNE_ERR_RET(
"fwd_port passed in lport private data is NULL\n");
txbuff = thd_private->txbuffs;
n_pkts = __rx_burst(fwd->pkt_api, pd, pd->rx_mbufs, fwd->burst);
if (n_pkts == PKTDEV_ADMIN_STATE_DOWN)
return -1;
for (i = 0; i < n_pkts; i++) {
uint8_t dst_lport = get_dst_lport(
pktmbuf_mtod(pd->rx_mbufs[i],
void *));
if (!dst)
dst = lport;
}
int nb_lports = jcfg_num_lports(fwd->jinfo);
for (int i = 0; i < nb_lports; i++) {
if (!dst)
continue;
}
return 0;
}
static int
{
struct fwd_port *pd = lport->priv_;
int n_pkts, n;
if (!pd)
CNE_ERR_RET(
"fwd_port passed in lport private data is NULL\n");
n_pkts = __rx_burst(fwd->pkt_api, pd, pd->rx_mbufs, fwd->burst);
if (n_pkts == PKTDEV_ADMIN_STATE_DOWN)
return -1;
if (n_pkts) {
for (int j = 0; j < n_pkts; j++)
n = __tx_flush(pd, fwd->pkt_api, pd->rx_mbufs, n_pkts);
if (n == PKTDEV_ADMIN_STATE_DOWN)
return -1;
pd->tx_overrun += n;
}
return 0;
}
static int
{
struct fwd_port *pd = lport->priv_;
int n_pkts, n;
if (!pd)
CNE_ERR_RET(
"fwd_port passed in lport private data is NULL\n");
if (fwd->pkt_api == PKTDEV_PKT_API)
else {
}
if (n_pkts > 0) {
for (int j = 0; j < n_pkts; j++) {
p[0] = 0x3cfdfee434c03cfd;
p[1] = 0xfee4384008004500;
p[2] = 0x002e60ac00004011;
p[3] = 0x8cecc6120001c612;
p[4] = 0x010104d2162e001a;
p[5] = 0x93c66b6c6d6e6f70;
p[6] = 0x7172737475767778;
p[7] = 0x797a3031;
}
n = __tx_flush(pd, fwd->pkt_api, tx_mbufs, n_pkts);
if (n == PKTDEV_ADMIN_STATE_DOWN)
return -1;
pd->tx_overrun += n;
}
return 0;
}
static int
{
struct fwd_port *pd = lport->priv_;
int n_pkts, n;
if (!pd)
CNE_ERR_RET(
"fwd_port passed in lport private data is NULL\n");
n_pkts = __rx_burst(fwd->pkt_api, pd, pd->rx_mbufs, fwd->burst);
if (n_pkts == PKTDEV_ADMIN_STATE_DOWN)
return -1;
if (fwd->pkt_api == PKTDEV_PKT_API)
else {
}
if (n_pkts > 0) {
for (int j = 0; j < n_pkts; j++) {
p[0] = 0x3cfdfee434c03cfd;
p[1] = 0xfee4384008004500;
p[2] = 0x002e60ac00004011;
p[3] = 0x8cecc6120001c612;
p[4] = 0x010104d2162e001a;
p[5] = 0x93c66b6c6d6e6f70;
p[6] = 0x7172737475767778;
p[7] = 0x797a3031;
}
n = __tx_flush(pd, fwd->pkt_api, tx_mbufs, n_pkts);
if (n == PKTDEV_ADMIN_STATE_DOWN)
return -1;
pd->tx_overrun += n;
}
return 0;
}
static void
destroy_per_thread_txbuff(
jcfg_thd_t *thd,
struct fwd_info *fwd)
{
if (thd->priv_) {
struct create_txbuff_thd_priv_t *thd_private = thd->priv_;
txbuff_t **txbuffs = thd_private->txbuffs;
int i;
for (i = 0; i < jcfg_num_lports(fwd->jinfo); i++) {
if (txbuffs[i])
txbuffs[i] = NULL;
}
free(thd_private->txbuffs);
thd_private->txbuffs = NULL;
free(thd->priv_);
thd->priv_ = NULL;
}
}
static int
{
struct create_txbuff_thd_priv_t *thd_private = arg;
txbuff_t **txbuffs = thd_private->txbuffs;
struct fwd_port *pd;
pd = lport->priv_;
if (!pd)
CNE_ERR_RET(
"fwd_port passed in lport private data is NULL\n");
pkt_api_t pkt_api = thd_private->pkt_api;
switch (pkt_api) {
case XSKDEV_PKT_API:
txbuffs[idx] =
break;
case PKTDEV_PKT_API:
txbuffs[idx] =
break;
default:
txbuffs[idx] = NULL;
break;
}
if (!txbuffs[idx])
CNE_ERR_RET(
"Failed to create txbuff for lport %d\n", idx);
return 0;
}
static int
create_per_thread_txbuff(
jcfg_thd_t *thd,
struct fwd_info *fwd)
{
if (thd->priv_) {
CNE_ERR("Expected thread's private data to be unused but it is %p\n", thd->priv_);
return -1;
}
struct create_txbuff_thd_priv_t *thd_private;
thd_private = calloc(1, sizeof(struct create_txbuff_thd_priv_t));
if (!thd_private) {
CNE_ERR_RET(
"Failed to allocate thd_private for %d lport(s)\n",
jcfg_num_lports(fwd->jinfo));
}
thd_private->txbuffs = calloc(jcfg_num_lports(fwd->jinfo),
sizeof(
txbuff_t *));
if (!thd_private->txbuffs) {
free(thd_private);
CNE_ERR_RET(
"Failed to allocate txbuff(s) for %d lport(s)\n", jcfg_num_lports(fwd->jinfo));
}
thd_private->pkt_api = fwd->pkt_api;
thd->priv_ = thd_private;
if (jcfg_lport_foreach(fwd->jinfo, _create_txbuff, thd->priv_)) {
destroy_per_thread_txbuff(thd, fwd);
return -1;
}
foreach_thd_lport (thd, lport)
((struct fwd_port *)lport->priv_)->thd = thd;
return 0;
}
void
thread_func(void *arg)
{
struct thread_func_arg_t *func_arg = arg;
struct fwd_info *fwd = func_arg->fwd;
struct {
} tests[] = {
{NULL},
{_drop_test},
{_loopback_test},
{_txonly_test},
{_fwd_test},
{acl_fwd_test},
{acl_fwd_test},
{_txonly_rx_test},
{NULL}
};
pthread_setaffinity_np(pthread_self(),
sizeof(cpu_set_t), &thd->
group->
lcore_bitmap);
if (pthread_barrier_wait(&fwd->barrier) > 0)
goto leave_no_lport;
if (fwd->test == FWD_TEST || fwd->test == ACL_STRICT_TEST || fwd->test == ACL_PERMISSIVE_TEST) {
if (create_per_thread_txbuff(thd, fwd))
cne_exit(
"Failed to create txbuff(s) for \"%s\" thread\n", thd->name);
}
cne_printf(
" [green]Forwarding Thread ID [orange]%d [green]on lcore [orange]%d[]\n", thd->
tid,
for (;;) {
foreach_thd_lport (thd, lport) {
if (thd->
quit == THD_QUIT)
goto leave;
usleep(1000);
continue;
}
if (tests[fwd->test].func(lport, fwd))
goto leave;
}
}
leave:
if (fwd->test == FWD_TEST || fwd->test == ACL_STRICT_TEST || fwd->test == ACL_PERMISSIVE_TEST)
destroy_per_thread_txbuff(thd, fwd);
leave_no_lport:
while (thd->
quit != THD_QUIT)
usleep(1000);
free(func_arg);
}
static int
{
return 0;
}
static int
{
int ret;
struct fwd_info *fwd = arg;
CNE_DEBUG("No lports attached to thread '%s'\n", thd->name);
return 0;
} else
CNE_DEBUG(
"Close %d lport%s for thread '%s'\n", thd->
lport_cnt,
(thd->
lport_cnt == 1) ?
"" :
"s", thd->name);
foreach_thd_lport (thd, lport) {
struct fwd_port *pd = lport->priv_;
cne_printf(
">>> [magenta]lport [red]%d[] - '[cyan]%s[]'\n", lport->
lpid, lport->name);
switch (fwd->pkt_api) {
case XSKDEV_PKT_API:
ret = 0;
break;
case PKTDEV_PKT_API:
break;
default:
ret = -1;
break;
}
if (ret < 0)
CNE_ERR("port_close() returned error\n");
}
return 0;
}
static int
{
uint32_t timo = TIMEOUT_VALUE;
while (--timo && thd->
quit != THD_DONE && idx > 0)
usleep(10000);
if (timo == 0)
return -1;
return 0;
}
static int
{
CNE_DEBUG("No lports attached to thread '%s'\n", thd->name);
return 0;
} else
CNE_DEBUG(
"Close %d lport%s for thread '%s'\n", thd->
lport_cnt,
(thd->
lport_cnt == 1) ?
"" :
"s", thd->name);
foreach_thd_lport (thd, lport) {
}
}
}
return 0;
}
static void
__on_exit(int val, void *arg, int exit_type)
{
struct fwd_info *fwd = arg;
switch (exit_type) {
if (val == SIGUSR1)
return;
cne_printf_pos(99, 1,
"\n>>> [cyan]Terminating with signal [green]%d[]\n", val);
fwd->timer_quit = 1;
break;
if (val)
cne_printf_pos(99, 1,
"\n>>> [cyan]Terminating with status [green]%d[]\n", val);
if (fwd) {
jcfg_thread_foreach(fwd->jinfo, _thread_quit, fwd);
jcfg_thread_foreach(fwd->jinfo, _thread_port_close, fwd);
jcfg_thread_foreach(fwd->jinfo, _check_thread_quit, fwd);
jcfg_thread_foreach(fwd->jinfo, _thread_cleanup, fwd);
udsc_close(fwd->xdp_uds);
fwd->timer_quit = 1;
}
break;
break;
default:
break;
}
fflush(stdout);
}
int
main(int argc, char **argv)
{
const char *tests[] = {
"Unknown", "Drop",
"Loopback",
"Tx Only",
"Forward",
"ACL Strict",
"ACL Permissive",
"Tx Only+RX",
NULL
};
const char *apis[] = {"Unknown", "XSKDEV", "PKTDEV", NULL};
int signals[] = {SIGINT, SIGUSR1, SIGTERM};
memset(&fwd_info, 0, sizeof(struct fwd_info));
if (
cne_init() || parse_args(argc, argv, fwd))
goto err;
cne_on_exit(__on_exit, fwd, signals, cne_countof(signals));
cne_printf(
"\n[yellow]*** [cyan:-:italic]CNDPFWD Forward Application[], "
"[green]API[]: [magenta:-:italic]%s[], "
"[green]Mode[]: [magenta:-:italic]%s[], "
"[green]Burst Size[]: [magenta]%d[] \n",
apis[fwd->pkt_api], tests[fwd->test], fwd->burst);
cne_printf(
" [green]Initial Thread ID [orange]%d [green]on lcore [orange]%d[]\n", getpid(),
if ((fwd->test == ACL_STRICT_TEST || fwd->test == ACL_PERMISSIVE_TEST) && acl_init(fwd) < 0)
goto err;
if (pthread_barrier_wait(&fwd->barrier) > 0)
fwd->timer_quit = 0;
for (;;) {
sleep(1);
if (fwd->timer_quit)
break;
if (fwd->opts.cli)
print_port_stats_all(fwd);
}
if (pthread_barrier_destroy(&fwd->barrier))
cne_printf(
">>> [cyan]Application Exiting[]: [green]Bye![]\n");
return 0;
err:
if (fwd->barrier_inited && pthread_barrier_destroy(&fwd->barrier))
CNE_ERR("Failed to destroy barrier\n");
cne_printf(
"\n*** [cyan]CNDPFWD Forward Application[], [green]API[]: [magenta]%s [green]PID[]: "
"[magenta]%d[] failed\n",
apis[fwd->pkt_api], getpid());
return -1;
}
CNDP_API int cne_init(void)
CNDP_API int cne_on_exit(on_exit_fn_t exit_fn, void *arg, int *signals, int nb_signals)
#define __cne_always_inline
#define CNE_ERR_GOTO(lbl,...)
#define cne_exit(format, args...)
CNDP_API int mmap_free(mmap_t *mmap)
CNDP_API int cne_printf_pos(int16_t r, int16_t c, const char *fmt,...)
CNDP_API int cne_printf(const char *fmt,...)
CNDP_API int cne_lcore_id(void)
CNDP_API jcfg_lport_t * jcfg_lport_by_index(jcfg_info_t *jinfo, int idx)
CNDP_API int metrics_destroy(void)
static uint16_t pktdev_tx_burst(uint16_t lport_id, pktmbuf_t **tx_pkts, uint16_t nb_pkts)
static uint16_t pktdev_rx_burst(uint16_t lport_id, pktmbuf_t **rx_pkts, const uint16_t nb_pkts)
CNDP_API int pktdev_buf_alloc(int lport_id, pktmbuf_t **bufs, uint16_t nb_bufs)
CNDP_API int pktdev_close(uint16_t lport_id)
#define pktmbuf_data_len(m)
#define pktmbuf_mtod(m, t)
static int pktmbuf_alloc_bulk(pktmbuf_info_t *pi, pktmbuf_t **mbufs, unsigned count)
static void pktmbuf_free_bulk(pktmbuf_t **mbufs, unsigned int count)
CNDP_API void pktmbuf_destroy(pktmbuf_info_t *pi)
CNDP_API txbuff_t * txbuff_pktdev_create(uint16_t size, txbuff_error_fn cbfn, void *cb_arg, uint16_t lport_id)
CNDP_API uint16_t txbuff_add(txbuff_t *buffer, pktmbuf_t *tx_pkt)
CNDP_API void txbuff_count_callback(txbuff_t *buffer, uint16_t sent, uint16_t unsent)
CNDP_API void txbuff_free(txbuff_t *buffer)
static int txbuff_count(txbuff_t *buffer)
CNDP_API txbuff_t * txbuff_xskdev_create(uint16_t size, txbuff_error_fn cbfn, void *cb_arg, void *xinfo)
CNDP_API uint16_t txbuff_flush(txbuff_t *buffer)
CNDP_API void uds_destroy(uds_info_t *info)
CNDP_API __cne_always_inline uint16_t xskdev_rx_burst(xskdev_info_t *xi, void **bufs, uint16_t nb_pkts)
CNDP_API void xskdev_socket_destroy(xskdev_info_t *xi)
CNDP_API __cne_always_inline uint16_t xskdev_tx_burst(xskdev_info_t *xi, void **bufs, uint16_t nb_pkts)