Simple pipeline example application which receives packets from one interface and passes them through 0-N worker stages before outputting them from a second network interface. The RX, worker, and TX stages are connected using plain queues and each stage is run on a separate CPU thread.
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <signal.h>
#include <unistd.h>
#include <inttypes.h>
#include <odp/helper/odph_api.h>
#define POOL_PKT_NUM 8192
#define POOL_PKT_LEN 1536
#define MAX_PKT_BURST 32
#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 3)
#define QUEUE_SIZE 1024
#define MAX_PKTIOS 2
#define DUMMY_HASH 1234567890
#define NO_PATH(file_name) (strrchr((file_name), '/') ? \
strrchr((file_name), '/') + 1 : (file_name))
struct {
uint64_t pps;
uint64_t rx_cnt;
uint64_t tx_cnt;
uint64_t rx_drops;
uint64_t tx_drops;
} s;
uint8_t padding[ODP_CACHE_LINE_SIZE];
} stats_t;
typedef struct thread_args_t {
stats_t stats;
} thread_args_t;
typedef struct {
char **if_names;
odph_ethaddr_t dst_addr;
int accuracy;
int extra_work;
int dst_change;
int src_change;
int dst_set;
int time;
int num_workers;
char *if_str;
} appl_args_t;
typedef struct {
odph_ethaddr_t src_addr;
odph_ethaddr_t dst_addr;
appl_args_t appl;
} global_data_t;
static global_data_t *global;
{
}
{
printf("Error: failed to open %s\n", name);
exit(1);
}
printf("Error: failed to config input queue for %s\n", name);
exit(1);
}
printf("Error: failed to config output queue for %s\n", name);
exit(1);
}
printf("Error: pktin queue query failed for %s\n", name);
exit(1);
}
printf("Error: pktout queue query failed for %s\n", name);
exit(1);
}
return pktio;
}
static inline unsigned int prep_events(
odp_packet_t pkt_tbl[],
unsigned int num)
{
unsigned int i;
unsigned int events = 0;
if (!global->appl.dst_change && !global->appl.src_change) {
return num;
}
for (i = 0; i < num; ++i) {
odph_ethhdr_t *eth;
continue;
}
if (global->appl.src_change)
eth->src = global->src_addr;
if (global->appl.dst_change)
eth->dst = global->dst_addr;
}
return events;
}
static inline int rx_thread(void *arg)
{
thread_args_t *thr_args = arg;
stats_t *stats = &thr_args->stats;
int pkts, events, sent, drops;
continue;
stats->s.rx_cnt += pkts;
events = prep_events(pkt_tbl, event_tbl, pkts);
drops = events - pkts;
stats->s.rx_drops += pkts - events;
sent = 0;
stats->s.tx_cnt += sent;
drops = events - sent;
stats->s.tx_drops += drops;
}
}
return 0;
}
static inline int tx_thread(void *arg)
{
thread_args_t *thr_args = arg;
stats_t *stats = &thr_args->stats;
int events, sent, tx_drops;
MAX_PKT_BURST);
continue;
stats->s.rx_cnt += events;
sent = 0;
stats->s.tx_cnt += sent;
tx_drops = events - sent;
stats->s.tx_drops += tx_drops;
}
}
events = 1;
while (events > 0) {
MAX_PKT_BURST);
if (events > 0)
}
return 0;
}
static inline void work_on_events(
odp_event_t event_tbl[],
unsigned int num)
{
unsigned int i;
for (i = 0; i < num; i++) {
printf("Dummy hash match\n");
}
}
static inline int worker_thread(
void *arg
ODP_UNUSED)
{
thread_args_t *thr_args = arg;
stats_t *stats = &thr_args->stats;
int events, sent, tx_drops;
int extra_work = global->appl.extra_work;
MAX_PKT_BURST);
continue;
stats->s.rx_cnt += events;
if (extra_work)
work_on_events(event_tbl, events);
sent = 0;
stats->s.tx_cnt += sent;
tx_drops = events - sent;
stats->s.tx_drops += tx_drops;
}
}
events = 1;
while (events > 0) {
MAX_PKT_BURST);
if (events > 0)
}
return 0;
}
int num_workers)
{
int num_threads = 0;
int i, cpu;
if (num_workers > MAX_WORKERS) {
printf("Worker count limited to MAX_WORKERS define (=%d)\n",
MAX_WORKERS);
num_workers = MAX_WORKERS;
}
num_threads = num_workers + 2;
if (num_workers != num_threads) {
printf("Error: Not enough available CPU cores: %d/%d\n",
num_workers, num_threads);
exit(1);
}
for (i = 0; i < num_threads; i++) {
if (i == 0)
else if (i == 1)
else
}
return num_threads;
}
static int print_speed_stats(int num_workers, stats_t **thr_stats,
int duration, int timeout)
{
uint64_t total_pkts = 0;
uint64_t pkts_prev = 0;
uint64_t maximum_pps = 0;
stats_t thr_stats_prev[num_workers];
int i;
int elapsed = 0;
int stats_enabled = 1;
int loop_forever = (duration == 0);
memset(thr_stats_prev, 0, sizeof(thr_stats_prev));
if (timeout <= 0) {
stats_enabled = 0;
timeout = 1;
}
do {
uint64_t total_rx_drops = 0;
uint64_t total_tx_drops = 0;
uint64_t pps;
sleep(timeout);
for (i = 0; i < num_workers; i++) {
uint64_t rx_cnt = thr_stats[i]->s.rx_cnt;
uint64_t tx_cnt = thr_stats[i]->s.tx_cnt;
uint64_t rx_drops = thr_stats[i]->s.rx_drops;
uint64_t tx_drops = thr_stats[i]->s.tx_drops;
if (i == (num_workers - 1))
total_pkts = tx_cnt;
total_rx_drops += rx_drops;
total_tx_drops += tx_drops;
pps = (tx_cnt - thr_stats_prev[i].s.tx_cnt) / timeout;
thr_stats_prev[i].s.pps = pps;
thr_stats_prev[i].s.rx_cnt = rx_cnt;
thr_stats_prev[i].s.tx_cnt = tx_cnt;
thr_stats_prev[i].s.rx_drops = rx_drops;
thr_stats_prev[i].s.tx_drops = tx_drops;
}
if (stats_enabled) {
printf("----------------------------------------\n");
for (i = 0; i < num_workers; i++) {
if (i == 0)
printf("RX thread: ");
else if (i == (num_workers - 1))
printf("TX thread: ");
else
printf("Worker %d: ", i - 1);
printf("%" PRIu64 " pps, "
"%" PRIu64 " rx drops, "
"%" PRIu64 " tx drops\n",
thr_stats_prev[i].s.pps,
thr_stats_prev[i].s.rx_drops,
thr_stats_prev[i].s.tx_drops);
}
pps = (total_pkts - pkts_prev) / timeout;
if (pps > maximum_pps)
maximum_pps = pps;
printf("TOTAL: %" PRIu64 " pps, "
"%" PRIu64 " rx drops, "
"%" PRIu64 " tx drops, "
"%" PRIu64 " max pps\n",
pps, total_rx_drops, total_tx_drops,
maximum_pps);
pkts_prev = total_pkts;
}
elapsed += timeout;
(elapsed < duration)));
if (stats_enabled)
printf("TEST RESULT: %" PRIu64 " maximum packets per second.\n",
maximum_pps);
return total_pkts > 0 ? 0 : -1;
}
static void print_info(char *progname, appl_args_t *appl_args)
{
printf("Running ODP appl: \"%s\"\n"
"-----------------\n"
"Using IFs: %s %s\n"
"Worker stages: %d\n"
"Extra work: %d\n\n",
progname, appl_args->if_names[0], appl_args->if_names[1],
appl_args->num_workers, appl_args->extra_work);
fflush(NULL);
}
static void usage(char *progname)
{
printf("\n"
"OpenDataPlane simple pipeline example application.\n"
"\n"
"Usage: %s [options]\n"
"\n"
" E.g. %s -i eth0,eth1 -e -w 3\n\n"
" ---- ---- ---- ---- ----\n"
" | RX | -> | W1 | -> | W2 | -> | W3 | -> | TX |\n"
" ---- ---- ---- ---- ----\n\n"
" In the above example,\n"
" each application stage is executed by a separate CPU thread and the stages\n"
" are connected using plain queues. The RX stage receives packets from eth0 and\n"
" enqueues them to the first worker stage (W1). The workers stages calculate\n"
" CRC-32C over packet data. After the final worker stage (W3) has processed\n"
" packets they are enqueued to the TX stage, which transmits the packets out\n"
" from interface eth1.\n"
"\n"
"Mandatory OPTIONS:\n"
" -i, --interface <name> Two eth interfaces (comma-separated, no spaces)\n"
"\n"
"Optional OPTIONS:\n"
" -a, --accuracy <sec> Time in seconds get print statistics\n"
" (default is 10 seconds).\n"
" -d, --dst_change <arg> 0: Don't change packets' dst eth addresses\n"
" 1: Change packets' dst eth addresses (default)\n"
" -s, --src_change <arg> 0: Don't change packets' src eth addresses\n"
" 1: Change packets' src eth addresses (default)\n"
" -r, --dst_addr <addr> Destination address\n"
" Requires also the -d flag to be set\n"
" -t, --time <sec> Time in seconds to run\n"
" -w, --workers <num> Number of worker stages (default 0)\n"
" -e, --extra-work Calculate CRC-32C over packet data in worker stage\n"
" -h, --help Display help and exit\n\n"
"\n", NO_PATH(progname), NO_PATH(progname)
);
}
static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
{
char *token;
size_t len;
int opt;
int i;
int if_count = 0;
static const struct option longopts[] = {
{"accuracy", required_argument, NULL, 'a'},
{"extra-work", no_argument, NULL, 'e'},
{"dst_addr", required_argument, NULL, 'r'},
{"dst_change", required_argument, NULL, 'd'},
{"src_change", required_argument, NULL, 's'},
{"interface", required_argument, NULL, 'i'},
{"time", required_argument, NULL, 't'},
{"workers", required_argument, NULL, 'w'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
static const char *shortopts = "+a:d:er:s:t:i:w:h";
appl_args->accuracy = 10;
appl_args->dst_change = 1;
appl_args->src_change = 1;
appl_args->time = 0;
appl_args->extra_work = 0;
while (1) {
opt = getopt_long(argc, argv, shortopts, longopts, NULL);
if (opt == -1)
break;
switch (opt) {
case 'a':
appl_args->accuracy = atoi(optarg);
break;
case 'd':
appl_args->dst_change = atoi(optarg);
break;
case 'e':
appl_args->extra_work = 1;
break;
case 'r':
len = strlen(optarg);
if (len == 0) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
len += 1;
if (odph_eth_addr_parse(&appl_args->dst_addr,
optarg) != 0) {
printf("invalid MAC address\n");
usage(argv[0]);
exit(EXIT_FAILURE);
}
appl_args->dst_set = 1;
break;
case 's':
appl_args->src_change = atoi(optarg);
break;
case 't':
appl_args->time = atoi(optarg);
break;
case 'i':
len = strlen(optarg);
if (len == 0) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
len += 1;
appl_args->if_str = malloc(len);
if (appl_args->if_str == NULL) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
strcpy(appl_args->if_str, optarg);
for (token = strtok(appl_args->if_str, ","), i = 0;
token != NULL;
token = strtok(NULL, ","), i++)
;
if_count = i;
if (if_count != 2) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
appl_args->if_names = calloc(if_count, sizeof(char *));
strcpy(appl_args->if_str, optarg);
for (token = strtok(appl_args->if_str, ","), i = 0;
token != NULL; token = strtok(NULL, ","), i++) {
appl_args->if_names[i] = token;
}
break;
case 'w':
appl_args->num_workers = atoi(optarg);
break;
case 'h':
usage(argv[0]);
exit(EXIT_SUCCESS);
break;
default:
break;
}
}
if (if_count != 2) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
optind = 1;
}
int main(int argc, char **argv)
{
odph_helper_options_t helper_options;
odph_thread_common_param_t thr_common;
odph_ethaddr_t new_addr;
thread_args_t *thr_args;
uint32_t pkt_len, seg_len, pkt_num;
int num_threads, num_workers;
int i;
int ret;
argc = odph_parse_options(argc, argv);
if (odph_options(&helper_options)) {
printf("Error: reading ODP helper options failed.\n");
exit(EXIT_FAILURE);
}
init_param.
mem_model = helper_options.mem_model;
printf("Error: ODP global init failed.\n");
exit(1);
}
printf("Error: ODP local init failed.\n");
exit(1);
}
ODP_CACHE_LINE_SIZE, 0);
printf("Error: shared mem reserve failed.\n");
exit(EXIT_FAILURE);
}
if (global == NULL) {
printf("Error: shared mem alloc failed.\n");
exit(EXIT_FAILURE);
}
memset(global, 0, sizeof(global_data_t));
signal(SIGINT, sig_handler);
parse_args(argc, argv, &global->appl);
num_threads = setup_thread_masks(&thr_mask_rx, &thr_mask_tx,
&thr_mask_worker,
global->appl.num_workers);
num_workers = num_threads - 2;
print_info(NO_PATH(argv[0]), &global->appl);
printf("Error: reading queue capability failed.\n");
exit(EXIT_FAILURE);
}
printf("Error: insufficient number of queues supported.\n");
exit(EXIT_FAILURE);
}
queue_param.
size = QUEUE_SIZE;
for (i = 0; i < num_threads; i++) {
&queue_param);
printf("Error: queue create failed.\n");
exit(EXIT_FAILURE);
}
global->queue[i] = queue;
}
printf("Error: reading pool capability failed.\n");
exit(EXIT_FAILURE);
}
pkt_len = POOL_PKT_LEN;
seg_len = POOL_PKT_LEN;
pkt_num = POOL_PKT_NUM;
printf("Error: packet pool create failed.\n");
exit(1);
}
global->if0 = create_pktio(global->appl.if_names[0], pool,
&global->if0in, &global->if0out);
global->if1 = create_pktio(global->appl.if_names[1], pool,
&global->if1in, &global->if1out);
ODPH_ETHADDR_LEN) != ODPH_ETHADDR_LEN) {
printf("Error: TX interface Ethernet address unknown\n");
exit(EXIT_FAILURE);
}
if (global->appl.dst_change) {
memset(&new_addr, 0, sizeof(odph_ethaddr_t));
if (global->appl.dst_set) {
memcpy(&new_addr, &global->appl.dst_addr,
sizeof(odph_ethaddr_t));
} else {
new_addr.addr[0] = 0x02;
new_addr.addr[5] = 1;
}
global->dst_addr = new_addr;
}
printf("Error: unable to start input interface\n");
exit(1);
}
printf("Error: unable to start output interface\n");
exit(1);
}
for (i = 0; i < num_threads; i++)
stats[i] = &global->thread[i].stats;
memset(thr_tbl, 0, sizeof(thr_tbl));
odph_thread_common_param_init(&thr_common);
thr_common.instance = instance;
thr_args = &global->thread[0];
thr_args->tx_queue = global->queue[0];
odph_thread_param_init(&thr_param[0]);
thr_param[0].start = rx_thread;
thr_param[0].arg = thr_args;
thr_common.cpumask = &thr_mask_rx;
odph_thread_create(thr_tbl, &thr_common, thr_param, 1);
for (i = 0; i < num_workers; i++) {
thr_args = &global->thread[i + 1];
thr_args->rx_queue = global->queue[i];
thr_args->tx_queue = global->queue[i + 1];
odph_thread_param_init(&thr_param[i]);
thr_param[i].start = worker_thread;
thr_param[i].arg = thr_args;
}
if (num_workers) {
thr_common.cpumask = &thr_mask_worker;
odph_thread_create(&thr_tbl[1], &thr_common, thr_param,
num_workers);
}
thr_args = &global->thread[num_threads - 1];
thr_args->rx_queue = global->queue[num_workers];
odph_thread_param_init(&thr_param[0]);
thr_param[0].start = tx_thread;
thr_param[0].arg = thr_args;
thr_common.cpumask = &thr_mask_tx;
odph_thread_create(&thr_tbl[num_threads - 1], &thr_common, thr_param,
1);
ret = print_speed_stats(num_threads, stats, global->appl.time,
global->appl.accuracy);
printf("Error: failed to stop interface %s\n", argv[1]);
exit(EXIT_FAILURE);
}
printf("Error: failed to stop interface %s\n", argv[2]);
exit(EXIT_FAILURE);
}
odph_thread_join(thr_tbl, num_threads);
free(global->appl.if_names);
free(global->appl.if_str);
printf("Error: failed to close interface %s\n", argv[1]);
exit(EXIT_FAILURE);
}
printf("Error: failed to close interface %s\n", argv[2]);
exit(EXIT_FAILURE);
}
for (i = 0; i < num_threads; i++) {
printf("Error: failed to destroy queue %d\n", i);
exit(EXIT_FAILURE);
}
}
printf("Error: pool destroy\n");
exit(EXIT_FAILURE);
}
printf("Error: shm free global data\n");
exit(EXIT_FAILURE);
}
printf("Error: term local\n");
exit(EXIT_FAILURE);
}
printf("Error: term global\n");
exit(EXIT_FAILURE);
}
return ret;
}
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
void odp_barrier_init(odp_barrier_t *barr, int count)
Initialize barrier with thread count.
void odp_barrier_wait(odp_barrier_t *barr)
Synchronize thread execution on barrier.
#define ODP_ALIGNED_CACHE
Defines type/struct/variable to be cache line size aligned.
#define odp_unlikely(x)
Branch unlikely taken.
#define ODP_UNUSED
Intentionally unused variables of functions.
void odp_cpumask_set(odp_cpumask_t *mask, int cpu)
Add CPU to mask.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
int odp_cpumask_first(const odp_cpumask_t *mask)
Find first set CPU in mask.
int odp_cpumask_next(const odp_cpumask_t *mask, int cpu)
Find next set CPU in mask.
void odp_cpumask_zero(odp_cpumask_t *mask)
Clear entire CPU mask.
void odp_event_free_multi(const odp_event_t event[], int num)
Free multiple events.
uint32_t odp_hash_crc32c(const void *data, uint32_t data_len, uint32_t init_val)
Calculate CRC-32C.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
int odp_pktio_mac_addr(odp_pktio_t pktio, void *mac_addr, int size)
Get the default MAC address of a packet IO interface.
void odp_pktin_queue_param_init(odp_pktin_queue_param_t *param)
Initialize packet input queue parameters.
void odp_pktio_param_init(odp_pktio_param_t *param)
Initialize pktio params.
int odp_pktio_close(odp_pktio_t pktio)
Close a packet IO interface.
int odp_pktout_queue(odp_pktio_t pktio, odp_pktout_queue_t queues[], int num)
Direct packet output queues.
void odp_pktio_config_init(odp_pktio_config_t *config)
Initialize packet IO configuration options.
odp_pktio_t odp_pktio_open(const char *name, odp_pool_t pool, const odp_pktio_param_t *param)
Open a packet IO interface.
int odp_pktio_config(odp_pktio_t pktio, const odp_pktio_config_t *config)
Configure packet IO interface options.
int odp_pktio_start(odp_pktio_t pktio)
Start packet receive and transmit.
#define ODP_PKTIO_INVALID
Invalid packet IO handle.
int odp_pktin_queue(odp_pktio_t pktio, odp_pktin_queue_t queues[], int num)
Direct packet input queues.
void odp_pktout_queue_param_init(odp_pktout_queue_param_t *param)
Initialize packet output queue parameters.
int odp_pktio_stop(odp_pktio_t pktio)
Stop packet receive and transmit.
int odp_pktin_recv(odp_pktin_queue_t queue, odp_packet_t packets[], int num)
Receive packets directly from an interface input queue.
int odp_pktout_send(odp_pktout_queue_t queue, const odp_packet_t packets[], int num)
Send packets directly to an interface output queue.
int odp_pktin_queue_config(odp_pktio_t pktio, const odp_pktin_queue_param_t *param)
Configure packet input queues.
int odp_pktout_queue_config(odp_pktio_t pktio, const odp_pktout_queue_param_t *param)
Configure packet output queues.
@ ODP_PKTIO_OP_MT_UNSAFE
Not multithread safe operation.
void odp_packet_from_event_multi(odp_packet_t pkt[], const odp_event_t ev[], int num)
Convert multiple packet events to packet handles.
odp_event_t odp_packet_to_event(odp_packet_t pkt)
Convert packet handle to event.
void odp_packet_to_event_multi(const odp_packet_t pkt[], odp_event_t ev[], int num)
Convert multiple packet handles to events.
uint32_t odp_packet_seg_len(odp_packet_t pkt)
Packet data length following the data pointer.
void odp_packet_prefetch(odp_packet_t pkt, uint32_t offset, uint32_t len)
Packet data prefetch.
void * odp_packet_data(odp_packet_t pkt)
Packet data pointer.
int odp_packet_has_eth(odp_packet_t pkt)
Check for Ethernet header.
odp_packet_t odp_packet_from_event(odp_event_t ev)
Get packet handle from event.
void odp_packet_free(odp_packet_t pkt)
Free packet.
void odp_packet_free_multi(const odp_packet_t pkt[], int num)
Free multiple packets.
@ ODP_PROTO_LAYER_L2
Layer L2 protocols (Ethernet, VLAN, etc)
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
int odp_pool_capability(odp_pool_capability_t *capa)
Query pool capabilities.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_PACKET
Packet pool.
int odp_queue_enq_multi(odp_queue_t queue, const odp_event_t events[], int num)
Enqueue multiple events to a queue.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
int odp_queue_capability(odp_queue_capability_t *capa)
Query queue capabilities.
#define ODP_QUEUE_INVALID
Invalid queue.
odp_queue_t odp_queue_create(const char *name, const odp_queue_param_t *param)
Queue create.
int odp_queue_destroy(odp_queue_t queue)
Destroy ODP queue.
int odp_queue_deq_multi(odp_queue_t queue, odp_event_t events[], int num)
Dequeue multiple events from a queue.
@ ODP_QUEUE_TYPE_PLAIN
Plain queue.
@ ODP_QUEUE_OP_MT_UNSAFE
Not multithread safe operation.
int odp_shm_free(odp_shm_t shm)
Free a contiguous block of shared memory.
#define ODP_SHM_INVALID
Invalid shared memory block.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align, uint32_t flags)
Reserve a contiguous block of shared memory.
void odp_sys_info_print(void)
Print system info.
#define ODP_THREAD_COUNT_MAX
Maximum number of threads supported in build time.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
Packet input queue parameters.
odp_pktio_op_mode_t op_mode
Operation mode.
Packet IO configuration options.
odp_pktio_parser_config_t parser
Packet input parser configuration.
odp_proto_layer_t layer
Protocol parsing level in packet input.
Packet output queue parameters.
odp_pktio_op_mode_t op_mode
Operation mode.
struct odp_pool_capability_t::@122 pkt
Packet pool capabilities
uint32_t max_num
Maximum number of buffers of any size.
uint32_t max_seg_len
Maximum packet segment data length in bytes.
uint32_t max_len
Maximum packet data length in bytes.
uint32_t num
Number of buffers in the pool.
odp_pool_type_t type
Pool type.
uint32_t len
Minimum length of 'num' packets.
uint32_t seg_len
Minimum number of packet data bytes that can be stored in the first segment of a newly allocated pack...
struct odp_pool_param_t::@126 pkt
Parameters for packet pools.
uint32_t max_size
Maximum number of events a plain (ODP_BLOCKING) queue can store simultaneously.
uint32_t max_num
Maximum number of plain (ODP_BLOCKING) queues of the default size.
struct odp_queue_capability_t::@140 plain
Plain queue capabilities.
odp_queue_op_mode_t enq_mode
Enqueue mode.
odp_queue_type_t type
Queue type.
odp_queue_op_mode_t deq_mode
Dequeue mode.