Packet IO basic performance test application. Runs a number of transmit and receive workers on separate cores, the transmitters generate packets at a defined rate and the receivers consume them. Generated packets are UDP and each packet is marked with a magic number in the UDP payload allowing receiver to distinguish them from other traffic.
Each test iteration runs for a fixed period, at the end of the iteration it is verified that the number of packets transmitted was as expected and that all transmitted packets were received.
The default mode is to run multiple test iterations at different rates to determine the maximum rate at which no packet loss occurs. Alternatively a single packet rate can be specified on the command line.
#include <odp/helper/odph_api.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#define TEST_SKIP 77
#define PKT_BUF_NUM (32 * 1024)
#define MAX_NUM_IFACES 2
#define TEST_HDR_MAGIC 0x92749451
#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
#define BATCH_LEN_MAX 32
#define RATE_SEARCH_INITIAL_PPS 1000000
#define RATE_SEARCH_ACCURACY_PPS 100000
#define SHUTDOWN_DELAY_NS (ODP_TIME_MSEC_IN_NS * 100)
#define T_SCALE 10
#define DEFAULT_DURATION 1
#define CACHE_ALIGN_ROUNDUP(x)\
((ODP_CACHE_LINE_SIZE) * \
(((x) + ODP_CACHE_LINE_SIZE - 1) / (ODP_CACHE_LINE_SIZE)))
#define PKT_HDR_LEN (sizeof(pkt_head_t) + ODPH_UDPHDR_LEN + \
ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN)
typedef struct {
unsigned int cpu_count;
int num_tx_workers;
int duration;
uint32_t tx_batch_len;
int schedule;
uint32_t rx_batch_len;
uint64_t pps;
int verbose;
unsigned pkt_len;
int search;
char *if_str;
const char *ifaces[MAX_NUM_IFACES];
int num_ifaces;
} test_args_t;
uint64_t rx_cnt;
uint64_t rx_ignore;
} pkt_rx_stats_t;
uint64_t tx_cnt;
uint64_t alloc_failures;
uint64_t enq_failures;
} pkt_tx_stats_t;
typedef struct {
test_args_t args;
pkt_rx_stats_t *rx_stats;
pkt_tx_stats_t *tx_stats;
uint8_t src_mac[ODPH_ETHADDR_LEN];
uint8_t dst_mac[ODPH_ETHADDR_LEN];
uint32_t rx_stats_size;
uint32_t tx_stats_size;
} test_globals_t;
typedef struct {
uint64_t pps_curr;
uint64_t pps_pass;
uint64_t pps_fail;
int warmup;
} test_status_t;
typedef struct {
int batch_len;
int duration;
uint64_t pps;
} thread_args_t;
typedef struct {
} pkt_head_t;
static test_globals_t *gbl_args;
{
odph_ethhdr_t *eth;
odph_ipv4hdr_t *ip;
odph_udphdr_t *udp;
char *buf;
uint32_t offset;
pkt_head_t pkt_hdr;
size_t payload_len;
payload_len = sizeof(pkt_hdr) + gbl_args->args.pkt_len;
payload_len + ODPH_UDPHDR_LEN +
ODPH_IPV4HDR_LEN + ODPH_ETHHDR_LEN);
offset = 0;
eth = (odph_ethhdr_t *)buf;
memcpy(eth->src.addr, gbl_args->src_mac, ODPH_ETHADDR_LEN);
memcpy(eth->dst.addr, gbl_args->dst_mac, ODPH_ETHADDR_LEN);
offset += ODPH_ETHHDR_LEN;
ip = (odph_ipv4hdr_t *)(buf + ODPH_ETHHDR_LEN);
ip->ver_ihl = ODPH_IPV4 << 4 | ODPH_IPV4HDR_IHL_MIN;
ODPH_IPV4HDR_LEN);
ip->ttl = 128;
ip->proto = ODPH_IPPROTO_UDP;
ip->chksum = 0;
odph_ipv4_csum_update(pkt);
offset += ODPH_IPV4HDR_LEN;
udp = (odph_udphdr_t *)(buf + offset);
udp->chksum = 0;
offset += ODPH_UDPHDR_LEN;
pkt_hdr.magic = TEST_HDR_MAGIC;
&pkt_hdr) != 0)
ODPH_ABORT("Failed to generate test packet.\n");
return pkt;
}
{
size_t l4_off;
pkt_head_t pkt_hdr;
l4_off = ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN;
l4_off + ODPH_UDPHDR_LEN,
sizeof(pkt_hdr), &pkt_hdr);
if (ret != 0)
return 0;
if (pkt_hdr.magic == TEST_HDR_MAGIC)
return 1;
return 0;
}
static int alloc_packets(
odp_packet_t *pkt_tbl,
int num_pkts)
{
int n;
uint16_t seq;
for (n = 0; n < num_pkts; ++n) {
pkt_tbl[n] = pktio_create_packet(seq + n);
break;
}
return n;
}
{
unsigned tx_drops;
unsigned sent = 0;
if (pkts == 0)
return 0;
while (sent < pkts) {
int ret;
sent += ret;
else
break;
}
tx_drops = pkts - sent;
return sent;
}
static int run_thread_tx(void *arg)
{
test_globals_t *globals;
int thr_id;
pkt_tx_stats_t *stats;
odp_time_t cur_time, send_time_end, send_duration;
uint32_t batch_len;
int unsent_pkts = 0;
thread_args_t *targs = arg;
batch_len = targs->batch_len;
if (batch_len > BATCH_LEN_MAX)
batch_len = BATCH_LEN_MAX;
stats = &globals->tx_stats[thr_id];
ODPH_ABORT("Failed to get output queue for thread %d\n",
thr_id);
send_duration =
burst_gap_end = cur_time;
unsigned alloc_cnt = 0, tx_cnt;
idle_start = cur_time;
continue;
}
stats->idle_ticks =
}
alloc_cnt = alloc_packets(tx_packet, batch_len - unsent_pkts);
if (alloc_cnt != batch_len)
stats->alloc_failures++;
tx_cnt = send_packets(pktout, tx_packet, alloc_cnt);
unsent_pkts = alloc_cnt - tx_cnt;
stats->enq_failures += unsent_pkts;
stats->tx_cnt += tx_cnt;
}
if (gbl_args->args.verbose)
printf(" %02d: TxPkts %-8" PRIu64 " EnqFail %-6" PRIu64
" AllocFail %-6" PRIu64 " Idle %" PRIu64 "ms\n",
thr_id, stats->tx_cnt, stats->enq_failures,
stats->alloc_failures,
return 0;
}
{
int n_ev = 0;
if (num_pkts == 0)
return 0;
if (num_pkts == 1) {
} else {
}
} else {
if (num_pkts == 1) {
} else {
event_tbl, num_pkts);
}
}
return n_ev;
}
static int run_thread_rx(void *arg)
{
test_globals_t *globals;
int thr_id, batch_len;
thread_args_t *targs = arg;
batch_len = targs->batch_len;
if (batch_len > BATCH_LEN_MAX)
batch_len = BATCH_LEN_MAX;
pkt_rx_stats_t *stats = &globals->rx_stats[thr_id];
if (gbl_args->args.schedule == 0) {
ODPH_ABORT("No input queue.\n");
}
while (1) {
int i, n_ev;
n_ev = receive_packets(queue, ev, batch_len);
for (i = 0; i < n_ev; ++i) {
if (pktio_pkt_has_magic(pkt))
stats->rx_cnt++;
else
stats->rx_ignore++;
}
}
break;
}
return 0;
}
static int process_results(uint64_t expected_tx_cnt,
test_status_t *status)
{
int fail = 0;
uint64_t drops = 0;
uint64_t rx_pkts = 0;
uint64_t tx_pkts = 0;
uint64_t attempted_pps;
int i;
char str[512];
int len = 0;
rx_pkts += gbl_args->rx_stats[i].rx_cnt;
tx_pkts += gbl_args->tx_stats[i].tx_cnt;
}
if (rx_pkts == 0) {
ODPH_ERR("no packets received\n");
return -1;
}
if (tx_pkts < (expected_tx_cnt - (expected_tx_cnt / 100))) {
fail = 1;
} else if (tx_pkts > rx_pkts) {
fail = 1;
drops = tx_pkts - rx_pkts;
}
attempted_pps = status->pps_curr;
len += snprintf(&str[len], sizeof(str) - 1 - len,
"PPS: %-8" PRIu64 " ", attempted_pps);
len += snprintf(&str[len], sizeof(str) - 1 - len,
"Succeeded: %-4s ", fail ? "No" : "Yes");
len += snprintf(&str[len], sizeof(str) - 1 - len,
"TxPkts: %-8" PRIu64 " ", tx_pkts);
len += snprintf(&str[len], sizeof(str) - 1 - len,
"RxPkts: %-8" PRIu64 " ", rx_pkts);
len += snprintf(&str[len], sizeof(str) - 1 - len,
"DropPkts: %-8" PRIu64 " ", drops);
printf("%s\n", str);
if (gbl_args->args.search == 0) {
printf("Result: %s\n", fail ? "FAILED" : "PASSED");
return fail ? -1 : 0;
}
if (fail && (status->pps_fail == 0 ||
attempted_pps < status->pps_fail)) {
status->pps_fail = attempted_pps;
} else if (attempted_pps > status->pps_pass) {
status->pps_pass = attempted_pps;
}
if (status->pps_fail == 0) {
status->pps_curr *= 2;
} else {
status->pps_curr = status->pps_pass +
((status->pps_fail - status->pps_pass) / 2);
}
if ((status->pps_fail - status->pps_pass) < RATE_SEARCH_ACCURACY_PPS) {
unsigned pkt_len = gbl_args->args.pkt_len + PKT_HDR_LEN;
int mbps = (pkt_len * status->pps_pass * 8) / 1024 / 1024;
printf("Maximum packet rate: %" PRIu64 " PPS (%d Mbps)\n",
status->pps_pass, mbps);
return 0;
}
return 1;
}
{
int num_workers, num_tx_workers, num_rx_workers;
int i, cpu;
num_workers =
gbl_args->args.cpu_count);
if (num_workers < 2) {
ODPH_ERR("Need at least two cores\n");
return TEST_SKIP;
}
if (num_workers > MAX_WORKERS) {
ODPH_DBG("Worker count limited to MAX_WORKERS define (=%d)\n",
MAX_WORKERS);
num_workers = MAX_WORKERS;
}
if (gbl_args->args.num_tx_workers) {
if (gbl_args->args.num_tx_workers > (num_workers - 1)) {
ODPH_ERR("Invalid TX worker count\n");
return -1;
}
num_tx_workers = gbl_args->args.num_tx_workers;
} else {
num_tx_workers = (num_workers + 1) / 2;
}
for (i = 0; i < num_workers; ++i) {
if (i < num_tx_workers)
else
}
return 0;
}
test_status_t *status)
{
odph_thread_t thread_tbl[MAX_WORKERS];
odph_thread_common_param_t thr_common;
odph_thread_param_t thr_param;
thread_args_t args_tx, args_rx;
uint64_t expected_tx_cnt;
int num_tx_workers, num_rx_workers;
memset(thread_tbl, 0, sizeof(thread_tbl));
memset(gbl_args->rx_stats, 0, gbl_args->rx_stats_size);
memset(gbl_args->tx_stats, 0, gbl_args->tx_stats_size);
expected_tx_cnt = status->pps_curr * gbl_args->args.duration / T_SCALE;
args_rx.batch_len = gbl_args->args.rx_batch_len;
odph_thread_common_param_init(&thr_common);
thr_common.instance = gbl_args->instance;
thr_common.cpumask = thd_mask_rx;
thr_common.share_param = 1;
odph_thread_param_init(&thr_param);
thr_param.start = run_thread_rx;
thr_param.arg = &args_rx;
odph_thread_create(thread_tbl, &thr_common, &thr_param, num_rx_workers);
args_tx.pps = status->pps_curr / num_tx_workers;
args_tx.duration = gbl_args->args.duration;
args_tx.batch_len = gbl_args->args.tx_batch_len;
odph_thread_common_param_init(&thr_common);
thr_common.instance = gbl_args->instance;
thr_common.cpumask = thd_mask_tx;
thr_common.share_param = 1;
odph_thread_param_init(&thr_param);
thr_param.start = run_thread_tx;
thr_param.arg = &args_tx;
odph_thread_create(&thread_tbl[num_rx_workers], &thr_common, &thr_param, num_tx_workers);
odph_thread_join(&thread_tbl[num_rx_workers], num_tx_workers);
odph_thread_join(thread_tbl, num_rx_workers);
if (!status->warmup)
return process_results(expected_tx_cnt, status);
return 1;
}
static int run_test(void)
{
int ret;
int i;
test_status_t status = {
.pps_curr = gbl_args->args.pps,
.pps_pass = 0,
.pps_fail = 0,
.warmup = 1,
};
ret = setup_txrx_masks(&txmask, &rxmask);
if (ret)
return ret;
printf("Starting test with params:\n");
printf("\tDuration (seconds): \t%d\n", gbl_args->args.duration);
printf("\tTransmit batch length:\t%" PRIu32 "\n",
gbl_args->args.tx_batch_len);
printf("\tReceive batch length: \t%" PRIu32 "\n",
gbl_args->args.rx_batch_len);
printf("\tPacket receive method:\t%s\n",
gbl_args->args.schedule ? "schedule" : "plain");
printf("\tInterface(s): \t");
for (i = 0; i < gbl_args->args.num_ifaces; ++i)
printf("%s ", gbl_args->args.ifaces[i]);
printf("\n");
run_test_single(&txmask, &rxmask, &status);
status.warmup = 0;
while (1) {
ret = run_test_single(&txmask, &rxmask, &status);
if (ret <= 0)
break;
}
return ret;
}
static odp_pktio_t create_pktio(
const char *iface,
int schedule)
{
params.
pkt.
len = PKT_HDR_LEN + gbl_args->args.pkt_len;
snprintf(pool_name, sizeof(pool_name), "pkt_pool_%s", iface);
if (schedule)
else
return pktio;
}
static int test_init(void)
{
const char *iface;
int schedule;
params.
pkt.
len = PKT_HDR_LEN + gbl_args->args.pkt_len;
¶ms);
ODPH_ABORT("Failed to create transmit pool\n");
iface = gbl_args->args.ifaces[0];
schedule = gbl_args->args.schedule;
if (schedule)
gbl_args->pktio_tx = create_pktio(iface, schedule);
if (gbl_args->args.num_ifaces > 1) {
iface = gbl_args->args.ifaces[1];
gbl_args->pktio_rx = create_pktio(iface, schedule);
} else {
gbl_args->pktio_rx = gbl_args->pktio_tx;
}
ODPH_ETHADDR_LEN);
ODPH_ETHADDR_LEN);
ODPH_ERR("failed to open pktio\n");
return -1;
}
ODPH_ERR("failed to configure pktio_tx queue\n");
return -1;
}
ODPH_ERR("failed to configure pktio_tx queue\n");
return -1;
}
if (gbl_args->args.num_ifaces > 1) {
ODPH_ERR("failed to configure pktio_rx queue\n");
return -1;
}
ODPH_ERR("failed to configure pktio_rx queue\n");
return -1;
}
}
return -1;
if (gbl_args->args.num_ifaces > 1 &&
return -1;
return 0;
}
{
return -1;
while (1) {
else
else
break;
}
return 0;
}
static int test_term(void)
{
int i;
int ret = 0;
if (gbl_args->pktio_tx != gbl_args->pktio_rx) {
ODPH_ERR("Failed to stop pktio_tx\n");
return -1;
}
ODPH_ERR("Failed to close pktio_tx\n");
ret = -1;
}
}
empty_inq(gbl_args->pktio_rx);
ODPH_ERR("Failed to stop pktio_rx\n");
return -1;
}
ODPH_ERR("Failed to close pktio_rx\n");
ret = -1;
}
for (i = 0; i < gbl_args->args.num_ifaces; ++i) {
snprintf(pool_name, sizeof(pool_name),
"pkt_pool_%s", gbl_args->args.ifaces[i]);
continue;
ODPH_ERR("Failed to destroy pool %s\n", pool_name);
ret = -1;
}
}
ODPH_ERR("Failed to destroy transmit pool\n");
ret = -1;
}
free(gbl_args->args.if_str);
ODPH_ERR("Failed to free test_globals\n");
ret = -1;
}
ODPH_ERR("Failed to free test_globals.rx_stats\n");
ret = -1;
}
ODPH_ERR("Failed to free test_globals.tx_stats\n");
ret = -1;
}
return ret;
}
static void usage(void)
{
printf("\nUsage: odp_pktio_perf [options]\n\n");
printf(" -c, --count <number> CPU count, 0=all available, default=2\n");
printf(" -t, --txcount <number> Number of CPUs to use for TX\n");
printf(" default: cpu_count+1/2\n");
printf(" -b, --txbatch <length> Number of packets per TX batch\n");
printf(" default: %d\n", BATCH_LEN_MAX);
printf(" -p, --plain Plain input queue for packet RX\n");
printf(" default: disabled (use scheduler)\n");
printf(" -R, --rxbatch <length> Number of packets per RX batch\n");
printf(" default: %d\n", BATCH_LEN_MAX);
printf(" -l, --length <length> Additional payload length in bytes\n");
printf(" default: 0\n");
printf(" -r, --rate <number> Attempted packet rate in PPS\n");
printf(" -i, --interface <list> List of interface names to use\n");
printf(" -d, --duration <secs> Duration of each test iteration\n");
printf(" -v, --verbose Print verbose information\n");
printf(" -h, --help This help\n");
printf("\n");
}
static void parse_args(int argc, char *argv[], test_args_t *args)
{
int opt;
static const struct option longopts[] = {
{"count", required_argument, NULL, 'c'},
{"txcount", required_argument, NULL, 't'},
{"txbatch", required_argument, NULL, 'b'},
{"plain", no_argument, NULL, 'p'},
{"rxbatch", required_argument, NULL, 'R'},
{"length", required_argument, NULL, 'l'},
{"rate", required_argument, NULL, 'r'},
{"interface", required_argument, NULL, 'i'},
{"duration", required_argument, NULL, 'd'},
{"verbose", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
static const char *shortopts = "+c:t:b:pR:l:r:i:d:vh";
args->cpu_count = 2;
args->num_tx_workers = 0;
args->tx_batch_len = BATCH_LEN_MAX;
args->rx_batch_len = BATCH_LEN_MAX;
args->duration = DEFAULT_DURATION;
args->pps = RATE_SEARCH_INITIAL_PPS;
args->search = 1;
args->schedule = 1;
args->verbose = 0;
while (1) {
opt = getopt_long(argc, argv, shortopts,
longopts, NULL);
if (opt == -1)
break;
switch (opt) {
case 'h':
usage();
exit(EXIT_SUCCESS);
case 'c':
args->cpu_count = atoi(optarg);
break;
case 't':
args->num_tx_workers = atoi(optarg);
break;
case 'd':
args->duration = atoi(optarg) * T_SCALE;
break;
case 'r':
args->pps = atoi(optarg);
args->search = 0;
args->verbose = 1;
break;
case 'i':
{
char *token;
args->if_str = malloc(strlen(optarg) + 1);
if (!args->if_str)
ODPH_ABORT("Failed to alloc iface storage\n");
strcpy(args->if_str, optarg);
for (token = strtok(args->if_str, ",");
token != NULL && args->num_ifaces < MAX_NUM_IFACES;
token = strtok(NULL, ","))
args->ifaces[args->num_ifaces++] = token;
}
break;
case 'p':
args->schedule = 0;
break;
case 'b':
args->tx_batch_len = atoi(optarg);
break;
case 'R':
args->rx_batch_len = atoi(optarg);
break;
case 'v':
args->verbose = 1;
break;
case 'l':
args->pkt_len = atoi(optarg);
break;
}
}
if (args->num_ifaces == 0) {
args->ifaces[0] = "loop";
args->num_ifaces = 1;
}
}
int main(int argc, char **argv)
{
int ret;
int max_thrs;
odph_helper_options_t helper_options;
argc = odph_parse_options(argc, argv);
if (odph_options(&helper_options)) {
ODPH_ERR("Error: reading ODP helper options failed.\n");
exit(EXIT_FAILURE);
}
init_param.
mem_model = helper_options.mem_model;
ODPH_ABORT("Failed global init.\n");
ODPH_ABORT("Failed local init.\n");
sizeof(test_globals_t), ODP_CACHE_LINE_SIZE, 0);
ODPH_ABORT("Shared memory reserve failed.\n");
if (gbl_args == NULL)
ODPH_ABORT("Shared memory reserve failed.\n");
memset(gbl_args, 0, sizeof(test_globals_t));
gbl_args->instance = instance;
gbl_args->rx_stats_size = max_thrs * sizeof(pkt_rx_stats_t);
gbl_args->tx_stats_size = max_thrs * sizeof(pkt_tx_stats_t);
gbl_args->rx_stats_size,
ODP_CACHE_LINE_SIZE, 0);
ODPH_ABORT("Shared memory reserve failed.\n");
if (gbl_args->rx_stats == NULL)
ODPH_ABORT("Shared memory reserve failed.\n");
memset(gbl_args->rx_stats, 0, gbl_args->rx_stats_size);
gbl_args->tx_stats_size,
ODP_CACHE_LINE_SIZE, 0);
ODPH_ABORT("Shared memory reserve failed.\n");
if (gbl_args->tx_stats == NULL)
ODPH_ABORT("Shared memory reserve failed.\n");
memset(gbl_args->tx_stats, 0, gbl_args->tx_stats_size);
parse_args(argc, argv, &gbl_args->args);
ret = test_init();
if (ret == 0) {
ret = run_test();
test_term();
}
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.
uint32_t odp_atomic_fetch_add_u32(odp_atomic_u32_t *atom, uint32_t val)
Fetch and add to 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.
uint32_t odp_u32be_t
unsigned 32bit big endian
odp_u16be_t odp_cpu_to_be_16(uint16_t cpu16)
Convert cpu native uint16_t to 16bit big endian.
#define odp_likely(x)
Branch likely taken.
odp_u32be_t odp_cpu_to_be_32(uint32_t cpu32)
Convert cpu native uint32_t to 32bit big endian.
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.
int odp_cpumask_count(const odp_cpumask_t *mask)
Count number of CPUs set in mask.
void odp_event_free(odp_event_t event)
Free event.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
#define ODP_EVENT_INVALID
Invalid event.
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_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.
int odp_pktin_event_queue(odp_pktio_t pktio, odp_queue_t queues[], int num)
Event queues for packet input.
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_pktio_stop(odp_pktio_t pktio)
Stop packet receive and transmit.
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_PKTIN_MODE_QUEUE
Packet input through plain event queues.
@ ODP_PKTIN_MODE_SCHED
Packet input through scheduler and scheduled event queues.
int odp_packet_l3_offset_set(odp_packet_t pkt, uint32_t offset)
Set layer 3 start offset.
void * odp_packet_data(odp_packet_t pkt)
Packet data pointer.
int odp_packet_l4_offset_set(odp_packet_t pkt, uint32_t offset)
Set layer 4 start offset.
odp_packet_t odp_packet_alloc(odp_pool_t pool, uint32_t len)
Allocate a packet from a packet pool.
int odp_packet_l2_offset_set(odp_packet_t pkt, uint32_t offset)
Set layer 2 start offset.
odp_packet_t odp_packet_from_event(odp_event_t ev)
Get packet handle from event.
int odp_packet_copy_from_mem(odp_packet_t pkt, uint32_t offset, uint32_t len, const void *src)
Copy data from memory to packet.
#define ODP_PACKET_INVALID
Invalid packet.
void odp_packet_free_multi(const odp_packet_t pkt[], int num)
Free multiple packets.
int odp_packet_copy_to_mem(odp_packet_t pkt, uint32_t offset, uint32_t len, void *dst)
Copy data from packet to memory.
@ ODP_PROTO_LAYER_NONE
No layers.
#define ODP_POOL_NAME_LEN
Maximum pool name length, including the null character.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
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()
odp_pool_t odp_pool_lookup(const char *name)
Find a pool by name.
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_PACKET
Packet pool.
#define ODP_QUEUE_INVALID
Invalid queue.
odp_event_t odp_queue_deq(odp_queue_t queue)
Dequeue an event from a queue.
odp_queue_type_t
Queue type.
odp_queue_type_t odp_queue_type(odp_queue_t queue)
Queue type.
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.
int odp_schedule_multi(odp_queue_t *from, uint64_t wait, odp_event_t events[], int num)
Schedule multiple events.
#define ODP_SCHED_NO_WAIT
Do not wait.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
odp_event_t odp_schedule(odp_queue_t *from, uint64_t wait)
Schedule an event.
odp_shm_t odp_shm_lookup(const char *name)
Lookup for a block of shared memory.
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.
int odp_thread_count_max(void)
Maximum thread count.
int odp_thread_id(void)
Get thread identifier.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
uint64_t odp_time_to_ns(odp_time_t time)
Convert time to nanoseconds.
odp_time_t odp_time_diff(odp_time_t t2, odp_time_t t1)
Time difference.
odp_time_t odp_time_sum(odp_time_t t1, odp_time_t t2)
Time sum.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
odp_time_t odp_time_local_from_ns(uint64_t ns)
Convert nanoseconds to local time.
void odp_time_wait_ns(uint64_t ns)
Wait the specified number of nanoseconds.
odp_time_t odp_time_local(void)
Current local time.
#define ODP_TIME_NULL
Zero time stamp.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
int odp_time_cmp(odp_time_t t2, odp_time_t t1)
Compare two times.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
Packet IO configuration options.
odp_pktio_parser_config_t parser
Packet input parser configuration.
odp_pktin_mode_t in_mode
Packet input mode.
odp_proto_layer_t layer
Protocol parsing level in packet input.
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.