API Reference Manual  1.50.0
odp_classifier.c

Classifier API example application

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) 2015-2018 Linaro Limited
* Copyright (c) 2019-2026 Nokia
* Copyright (c) 2020 Marvell
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <inttypes.h>
#include <signal.h>
#include <odp_api.h>
#include <odp/helper/odph_api.h>
#include <strings.h>
#include <errno.h>
#include <stdio.h>
#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
#define MAX_PKT_BURST 64
#define DEF_PKT_BURST 32
#define SHM_PKT_POOL_SIZE 10000
#define SHM_PKT_POOL_BUF_SIZE 1856
#define MAX_PMR_COUNT 32
#define DISPLAY_STRING_LEN 32
#define MAX_VAL_SIZE 16
#define NO_PATH(file_name) (strrchr((file_name), '/') ? \
strrchr((file_name), '/') + 1 : (file_name))
typedef struct {
odp_queue_t queue;
odp_pool_t pool;
odp_cos_t cos;
odp_pmr_t pmr;
odp_atomic_u64_t queue_pkt_count;
odp_atomic_u64_t pool_pkt_count;
char cos_name[ODP_COS_NAME_LEN];
char src_cos_name[ODP_COS_NAME_LEN];
struct {
uint8_t value_be[MAX_VAL_SIZE];
uint8_t mask_be[MAX_VAL_SIZE];
uint32_t val_sz;
uint32_t offset;
} rule;
char value[DISPLAY_STRING_LEN];
char mask[DISPLAY_STRING_LEN];
int has_src_cos;
} global_statistics;
typedef struct {
char cos_name[ODP_COS_NAME_LEN];
uint64_t count;
} ci_pass_counters;
typedef struct {
char cos_name[ODP_COS_NAME_LEN];
odp_aggr_enq_profile_t cos_enq_prof;
uint32_t num_aggr;
} cos_q_param_t;
typedef struct {
odp_pktout_queue_t pktout[MAX_WORKERS];
int num_pktout;
global_statistics stats[MAX_PMR_COUNT];
ci_pass_counters ci_pass_rules[MAX_PMR_COUNT];
cos_q_param_t cos_q_param[MAX_PMR_COUNT];
int policy_count;
int num_ci_pass_rules;
int num_cos_q_param;
int appl_mode;
odp_atomic_u64_t total_packets;
unsigned int cpu_count;
uint32_t time;
char *if_name;
int shutdown;
int shutdown_sig;
int verbose;
int promisc_mode;
int classifier_enable;
int parse_layer;
int cos_pools;
int pool_size;
int burst_size;
uint32_t vector_size;
} appl_args_t;
enum packet_mode {
APPL_MODE_DROP,
APPL_MODE_REPLY
};
static appl_args_t *appl_args_gbl;
static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len);
static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len);
static int parse_args(int argc, char *argv[], appl_args_t *appl_args);
static void print_info(char *progname, appl_args_t *appl_args);
static void usage(void);
static inline int check_ci_pass_count(appl_args_t *args)
{
int i, j;
uint64_t count;
if (args->num_ci_pass_rules == 0)
return 0;
for (i = 0; i < args->num_ci_pass_rules; i++) {
for (j = 0; j < args->policy_count; j++) {
if (!strcmp(args->stats[j].cos_name,
args->ci_pass_rules[i].cos_name)) {
count = odp_atomic_load_u64(&args->stats[i].queue_pkt_count);
if (args->ci_pass_rules[i].count > count) {
ODPH_ERR("Error: Cos = %s, expected packets = %" PRIu64 ","
"received packet = %" PRIu64 "\n",
args->stats[j].cos_name,
args->ci_pass_rules[i].count, count);
return -1;
}
break;
}
}
if (j == args->policy_count) {
ODPH_ERR("Error: invalid Cos:%s specified for CI pass count\n",
args->ci_pass_rules[i].cos_name);
return -1;
}
}
return 0;
}
static inline void print_cls_statistics(appl_args_t *args)
{
int i;
uint32_t timeout;
int infinite = 0;
printf("\n");
for (i = 0; i < 40; i++)
printf("-");
printf("\n");
/* print statistics */
printf("CLASSIFIER EXAMPLE STATISTICS\n");
for (i = 0; i < 40; i++)
printf("-");
printf("\n");
printf("CONFIGURATION\n");
printf("\n");
printf("COS\tVALUE\t\tMASK\n");
for (i = 0; i < 40; i++)
printf("-");
printf("\n");
for (i = 0; i < args->policy_count - 1; i++) {
printf("%s\t", args->stats[i].cos_name);
printf("%s\t", args->stats[i].value);
printf("%s\n", args->stats[i].mask);
}
printf("\n");
printf("RECEIVED PACKETS\n");
for (i = 0; i < 40; i++)
printf("-");
printf("\n");
for (i = 0; i < args->policy_count; i++)
printf("%-12s |", args->stats[i].cos_name);
printf("%-6s %-6s", "Total", "Mpps");
printf("\n");
for (i = 0; i < args->policy_count; i++)
printf("%-6s %-6s|", "queue", "pool");
printf("\n");
timeout = args->time;
/* Incase if default value is given for timeout
run the loop infinitely */
if (timeout == 0)
infinite = 1;
uint64_t total_packets, last_total_packets = 0;
odp_time_t start = odp_time_local(), end;
float mpps;
for (; timeout > 0 || infinite; timeout--) {
sleep(1);
for (i = 0; i < args->policy_count; i++) {
printf("%-6" PRIu64 " ",
odp_atomic_load_u64(&args->stats[i]
.queue_pkt_count));
printf("%-6" PRIu64 "|",
odp_atomic_load_u64(&args->stats[i]
.pool_pkt_count));
}
end = odp_time_local();
total_packets = odp_atomic_load_u64(&args->total_packets);
mpps = (total_packets - last_total_packets) /
(odp_time_diff_ns(end, start) / 1000.0);
printf("%-6" PRIu64 " %-6.3f\n", total_packets, mpps);
last_total_packets = total_packets;
start = end;
if (args->shutdown_sig)
break;
}
printf("\n");
}
static int parse_custom(const char *str, uint8_t *buf_be, int max_size)
{
int i, len;
/* hex string without 0x prefix */
len = strlen(str);
if (len > 2 * max_size)
return -1;
for (i = 0; i < len; i += 2)
if (sscanf(&str[i], "%2" SCNx8, &buf_be[i / 2]) != 1)
return -1;
return len / 2;
}
static odp_pktio_t create_pktio(const char *dev, odp_pool_t pool)
{
odp_pktio_t pktio;
odp_pktio_param_t pktio_param;
odp_pktout_queue_param_t pktout_queue_param;
int num_tx;
odp_pktio_param_init(&pktio_param);
/* Open a packet IO instance */
pktio = odp_pktio_open(dev, pool, &pktio_param);
if (pktio == ODP_PKTIO_INVALID) {
ODPH_ERR("pktio create failed for %s\n", dev);
exit(EXIT_FAILURE);
}
if (odp_pktio_capability(pktio, &capa)) {
ODPH_ERR("pktio capability failed for %s\n", dev);
exit(EXIT_FAILURE);
}
pktin_param.classifier_enable = appl_args_gbl->classifier_enable;
if (odp_pktin_queue_config(pktio, &pktin_param)) {
ODPH_ERR("pktin queue config failed for %s\n", dev);
exit(EXIT_FAILURE);
}
num_tx = appl_args_gbl->cpu_count;
if (num_tx > (int)capa.max_output_queues) {
printf("Sharing %i output queues between %i workers\n",
capa.max_output_queues, num_tx);
num_tx = capa.max_output_queues;
}
appl_args_gbl->num_pktout = num_tx;
odp_pktout_queue_param_init(&pktout_queue_param);
pktout_queue_param.num_queues = num_tx;
if (odp_pktout_queue_config(pktio, &pktout_queue_param)) {
ODPH_ERR("pktout queue config failed for %s\n", dev);
exit(EXIT_FAILURE);
}
if (odp_pktout_queue(pktio, appl_args_gbl->pktout, num_tx) != num_tx) {
ODPH_ERR("Pktout queue query failed: %s\n", dev);
exit(EXIT_FAILURE);
}
if (appl_args_gbl->promisc_mode && odp_pktio_promisc_mode(pktio) != 1) {
if (!capa.set_op.op.promisc_mode) {
ODPH_ERR("enabling promisc mode not supported %s\n", dev);
exit(EXIT_FAILURE);
}
if (odp_pktio_promisc_mode_set(pktio, true)) {
ODPH_ERR("failed to enable promisc mode for %s\n", dev);
exit(EXIT_FAILURE);
}
}
printf("created pktio:%" PRIu64 ", dev:%s", odp_pktio_to_u64(pktio), dev);
odph_ethaddr_t mac;
if (odp_pktio_mac_addr(pktio, &mac, sizeof(mac)) == sizeof(mac)) {
printf(", mac");
for (int c = 0; c < (int)sizeof(mac); c++)
printf(":%02x", mac.addr[c]);
}
printf("\n");
cfg.parser.layer = appl_args_gbl->parse_layer;
if (odp_pktio_config(pktio, &cfg)) {
ODPH_ERR("failed to configure pktio %s\n", dev);
exit(EXIT_FAILURE);
}
return pktio;
}
static void process_packets(odp_packet_t pkts[], int num, odp_queue_t in_q,
odp_pktout_queue_t out_q, appl_args_t *appl, int thr,
odp_bool_t was_vector)
{
odp_pool_t pool;
int i, j, dropped, sent;
global_statistics *stats;
unsigned long err_cnt = 0;
if (odp_unlikely(appl->verbose)) {
const char *orig = was_vector ? "vector" : "packet";
for (j = 0; j < num; j++) {
uint32_t len = odp_packet_len(pkts[j]);
printf("Origin: %s\n", orig);
if (odp_queue_info(in_q, &info) == 0)
printf("Queue: %s\n", info.name);
if (len > 96)
len = 96;
odp_packet_print_data(pkts[j], 0, len);
}
}
/* Total packets received */
odp_atomic_add_u64(&appl->total_packets, num);
/* Drop packets with errors */
dropped = drop_err_pkts(pkts, num);
if (odp_unlikely(dropped)) {
num -= dropped;
err_cnt += dropped;
ODPH_ERR("Drop frame - err_cnt:%lu\n", err_cnt);
}
for (j = 0; j < num; j++) {
pool = odp_packet_pool(pkts[j]);
for (i = 0; i < MAX_PMR_COUNT; i++) {
stats = &appl->stats[i];
if (in_q == stats->queue)
odp_atomic_inc_u64(&stats->queue_pkt_count);
if (pool == stats->pool)
odp_atomic_inc_u64(&stats->pool_pkt_count);
}
}
if (appl->appl_mode == APPL_MODE_DROP) {
return;
}
/* Swap Eth MACs and possibly IP-addrs before sending back */
swap_pkt_addrs(pkts, num);
sent = odp_pktout_send(out_q, pkts, num);
sent = sent < 0 ? 0 : sent;
if (sent != num) {
ODPH_ERR(" [%i] Packet send failed\n", thr);
odp_packet_free_multi(pkts + sent, num - sent);
}
}
static int pktio_receive_thread(void *arg)
{
const int thr = odp_thread_id();
odp_packet_t single_pkts[MAX_PKT_BURST];
odp_event_t ev, evs[MAX_PKT_BURST], *ev_tbl;
int num_recv, num_pkts, vector_size;
odp_queue_t queue;
appl_args_t *appl = (appl_args_t *)arg;
const uint64_t wait_time = odp_schedule_wait_time(100 * ODP_TIME_MSEC_IN_NS);
odp_pktout_queue_t pktout = appl_args_gbl->pktout[thr % appl_args_gbl->num_pktout];
/* Loop packets */
for (;;) {
if (appl->shutdown)
break;
/* Use schedule to get buf from any input queue */
num_recv = odp_schedule_multi(&queue, wait_time, evs, appl_args_gbl->burst_size);
/* Loop back to receive packets incase of invalid event */
if (odp_unlikely(!num_recv))
continue;
num_pkts = 0;
for (int i = 0; i < num_recv; i++) {
ev = evs[i];
if (odp_event_type(ev) == ODP_EVENT_VECTOR) {
vector_size = odp_event_vector_tbl(evv, &ev_tbl);
odp_packet_t vector_pkts[vector_size];
odp_packet_from_event_multi(vector_pkts, ev_tbl, vector_size);
process_packets(vector_pkts, vector_size, queue, pktout, appl, thr,
true);
continue;
}
single_pkts[num_pkts++] = odp_packet_from_event(ev);
}
if (num_pkts > 0)
process_packets(single_pkts, num_pkts, queue, pktout, appl, thr, false);
}
return 0;
}
static odp_pool_t create_vector_pool(appl_args_t *args)
{
/* For now, singleton pool */
if (pool != ODP_POOL_INVALID)
return pool;
param.event_vector.num = args->pool_size;
param.event_vector.max_size = args->vector_size;
pool = odp_pool_create("vector_pool", &param);
if (pool == ODP_POOL_INVALID) {
ODPH_ERR("Error: failed to create event vector pool\n");
exit(EXIT_FAILURE);
}
printf("created singleton event vector pool: %" PRIu64 ", size: %u, vector size: %u\n",
odp_pool_to_u64(pool), args->pool_size, args->vector_size);
return pool;
}
static void destroy_vector_pool(odp_pool_t pool)
{
/* Destroy the singleton pool once */
static odp_bool_t is_destroyed;
if (is_destroyed)
return;
is_destroyed = true;
}
static odp_pool_t pool_create(const char *name)
{
odp_pool_param_t pool_params;
if (!appl_args_gbl->cos_pools && pool != ODP_POOL_INVALID)
return pool;
odp_pool_param_init(&pool_params);
pool_params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
pool_params.pkt.len = SHM_PKT_POOL_BUF_SIZE;
pool_params.pkt.num = appl_args_gbl->pool_size;
pool_params.type = ODP_POOL_PACKET;
pool = odp_pool_create(name, &pool_params);
if (pool == ODP_POOL_INVALID) {
ODPH_ERR("Error: failed to create pool %s\n", name);
exit(EXIT_FAILURE);
}
return pool;
}
static odp_cos_t configure_default_cos(odp_pktio_t pktio, appl_args_t *args)
{
const char *queue_name = "DefaultQueue";
const char *pool_name = "DefaultPool";
const char *cos_name = "DefaultCos";
odp_queue_t queue_default;
odp_pool_t pool_default;
odp_cos_t cos_default;
global_statistics *stats = args->stats;
queue_default = odp_queue_create(queue_name, &qparam);
if (queue_default == ODP_QUEUE_INVALID) {
ODPH_ERR("Error: default queue create failed\n");
exit(EXIT_FAILURE);
}
pool_default = pool_create(pool_name);
cls_param.pool = pool_default;
cls_param.queue = queue_default;
cos_default = odp_cls_cos_create(cos_name, &cls_param);
if (cos_default == ODP_COS_INVALID) {
ODPH_ERR("Error: default cos create failed\n");
exit(EXIT_FAILURE);
}
if (0 > odp_pktio_default_cos_set(pktio, cos_default)) {
ODPH_ERR("odp_pktio_default_cos_set failed\n");
exit(EXIT_FAILURE);
}
stats[args->policy_count].cos = cos_default;
/* add default queue to global stats */
stats[args->policy_count].queue = queue_default;
if (appl_args_gbl->cos_pools)
stats[args->policy_count].pool = pool_default;
snprintf(stats[args->policy_count].cos_name,
sizeof(stats[args->policy_count].cos_name),
"%s", cos_name);
odp_atomic_init_u64(&stats[args->policy_count].queue_pkt_count, 0);
odp_atomic_init_u64(&stats[args->policy_count].pool_pkt_count, 0);
args->policy_count++;
return cos_default;
}
static cos_q_param_t *find_cos_q_param(appl_args_t *args, const char *name)
{
int i;
for (i = 0; i < args->num_cos_q_param; i++) {
if (strcmp(args->cos_q_param[i].cos_name, name) == 0)
return &args->cos_q_param[i];
}
return NULL;
}
static int find_cos(appl_args_t *args, const char *name, odp_cos_t *cos)
{
global_statistics *stats;
int i;
for (i = 0; i < args->policy_count - 1; i++) {
stats = &args->stats[i];
if (strcmp(stats->cos_name, name) == 0) {
*cos = stats->cos;
return 0;
}
}
return -1;
}
static void configure_cos(odp_cos_t default_cos, appl_args_t *args)
{
char cos_name[ODP_COS_NAME_LEN];
char pool_name[ODP_POOL_NAME_LEN];
const char *queue_name;
int i;
cos_q_param_t *cq_param;
global_statistics *stats;
for (i = 0; i < args->policy_count - 1; i++) {
stats = &args->stats[i];
queue_name = stats->cos_name;
cq_param = find_cos_q_param(args, queue_name);
if (cq_param != NULL) {
qparam.sched.sync = cq_param->q_sync;
qparam.sched.prio = cq_param->q_prio;
qparam.num_aggr = cq_param->num_aggr;
qparam.aggr = &cq_param->q_aggr;
cls_param.aggr_enq_profile = cq_param->cos_enq_prof;
} else {
}
stats->queue = odp_queue_create(queue_name, &qparam);
if (ODP_QUEUE_INVALID == stats->queue) {
ODPH_ERR("odp_queue_create failed\n");
exit(EXIT_FAILURE);
}
snprintf(pool_name, sizeof(pool_name), "%sPool%d",
args->stats[i].cos_name, i);
snprintf(cos_name, sizeof(cos_name), "CoS%s",
stats->cos_name);
cls_param.pool = pool_create(pool_name);
if (appl_args_gbl->cos_pools)
stats->pool = cls_param.pool;
if (cq_param != NULL && cq_param->num_aggr > 0)
cls_param.queue = odp_queue_aggr(stats->queue, 0);
else
cls_param.queue = stats->queue;
stats->cos = odp_cls_cos_create(cos_name, &cls_param);
if (ODP_COS_INVALID == stats->cos) {
ODPH_ERR("odp_cls_cos_create failed\n");
exit(EXIT_FAILURE);
}
odp_atomic_init_u64(&stats->queue_pkt_count, 0);
odp_atomic_init_u64(&stats->pool_pkt_count, 0);
}
for (i = 0; i < args->policy_count - 1; i++) {
odp_pmr_param_t pmr_param;
odp_cos_t src_cos = default_cos;
stats = &args->stats[i];
if (stats->has_src_cos) {
if (find_cos(args, stats->src_cos_name, &src_cos)) {
ODPH_ERR("find_cos failed\n");
exit(EXIT_FAILURE);
}
}
pmr_param.term = stats->rule.term;
pmr_param.match.value = stats->rule.value_be;
pmr_param.match.mask = stats->rule.mask_be;
pmr_param.val_sz = stats->rule.val_sz;
pmr_param.offset = stats->rule.offset;
stats->pmr = odp_cls_pmr_create(&pmr_param, 1, src_cos,
stats->cos);
if (stats->pmr == ODP_PMR_INVALID) {
ODPH_ERR("odp_pktio_pmr_cos failed\n");
exit(EXIT_FAILURE);
}
}
}
static void sig_handler(int signo)
{
(void)signo;
if (appl_args_gbl == NULL)
return;
appl_args_gbl->shutdown_sig = 1;
}
int main(int argc, char *argv[])
{
odph_helper_options_t helper_options;
odph_thread_t thread_tbl[MAX_WORKERS];
odp_pool_t pool;
int num_workers;
int i;
odp_cpumask_t cpumask;
char cpumaskstr[ODP_CPUMASK_STR_SIZE];
odp_pktio_t pktio;
appl_args_t *args;
odp_cos_t default_cos;
odp_shm_t shm;
int ret;
odp_instance_t instance;
odp_init_t init_param;
odph_thread_common_param_t thr_common;
odph_thread_param_t thr_param;
signal(SIGINT, sig_handler);
/* Let helper collect its own arguments (e.g. --odph_proc) */
argc = odph_parse_options(argc, argv);
if (odph_options(&helper_options)) {
ODPH_ERR("Error: reading ODP helper options failed\n");
exit(EXIT_FAILURE);
}
odp_init_param_init(&init_param);
init_param.mem_model = helper_options.mem_model;
/* Init ODP before calling anything else */
if (odp_init_global(&instance, &init_param, NULL)) {
ODPH_ERR("Error: ODP global init failed\n");
exit(EXIT_FAILURE);
}
/* Init this thread */
ODPH_ERR("Error: ODP local init failed\n");
exit(EXIT_FAILURE);
}
/* Reserve memory for args from shared mem */
shm = odp_shm_reserve("cls_shm_args", sizeof(appl_args_t),
ODP_CACHE_LINE_SIZE, 0);
if (shm == ODP_SHM_INVALID) {
ODPH_ERR("Error: shared mem reserve failed\n");
exit(EXIT_FAILURE);
}
args = odp_shm_addr(shm);
if (args == NULL) {
ODPH_ERR("Error: shared mem alloc failed\n");
exit(EXIT_FAILURE);
}
appl_args_gbl = args;
memset(args, 0, sizeof(*args));
/* Parse and store the application arguments */
if (parse_args(argc, argv, args))
goto args_error;
/* Print both system and application information */
print_info(NO_PATH(argv[0]), args);
num_workers = MAX_WORKERS;
if (args->cpu_count && args->cpu_count < MAX_WORKERS)
num_workers = args->cpu_count;
/* Get default worker cpumask */
num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
(void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
printf("num worker threads: %i\n", num_workers);
printf("first CPU: %i\n", odp_cpumask_first(&cpumask));
printf("cpu mask: %s\n", cpumaskstr);
/* Create packet pool */
pool = pool_create("packet_pool");
for (i = 0; i < args->num_cos_q_param; i++) {
if (args->cos_q_param[i].num_aggr > 0)
args->cos_q_param[i].q_aggr.pool = create_vector_pool(args);
}
/* Configure scheduler */
/* odp_pool_print(pool); */
odp_atomic_init_u64(&args->total_packets, 0);
/* create pktio per interface */
pktio = create_pktio(args->if_name, pool);
/* configure default Cos */
default_cos = configure_default_cos(pktio, args);
configure_cos(default_cos, args);
printf("\n");
if (odp_pktio_start(pktio)) {
ODPH_ERR("Error: unable to start pktio\n");
exit(EXIT_FAILURE);
}
/* Create and init worker threads */
memset(thread_tbl, 0, sizeof(thread_tbl));
odph_thread_common_param_init(&thr_common);
odph_thread_param_init(&thr_param);
thr_param.start = pktio_receive_thread;
thr_param.arg = args;
thr_param.thr_type = ODP_THREAD_WORKER;
thr_common.instance = instance;
thr_common.cpumask = &cpumask;
thr_common.share_param = 1;
odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers);
if (args->verbose == 0) {
print_cls_statistics(args);
} else {
int timeout = args->time;
for (i = 0; timeout == 0 || i < timeout; i++) {
if (args->shutdown_sig)
break;
sleep(1);
}
}
args->shutdown = 1;
odph_thread_join(thread_tbl, num_workers);
if (check_ci_pass_count(args)) {
ODPH_ERR("Error: Packet count verification failed\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < args->policy_count; i++) {
if ((i != args->policy_count - 1) &&
odp_cls_pmr_destroy(args->stats[i].pmr))
ODPH_ERR("err: odp_cls_pmr_destroy for %d\n", i);
if (odp_cos_destroy(args->stats[i].cos))
ODPH_ERR("err: odp_cos_destroy for %d\n", i);
if (odp_queue_destroy(args->stats[i].queue))
ODPH_ERR("err: odp_queue_destroy for %d\n", i);
if (args->cos_pools && odp_pool_destroy(args->stats[i].pool))
ODPH_ERR("err: odp_pool_destroy for %d\n", i);
}
if (odp_pktio_close(pktio))
ODPH_ERR("err: close pktio error\n");
for (i = 0; i < args->num_cos_q_param; i++) {
cos_q_param_t *cos_q_param = &args->cos_q_param[i];
if (cos_q_param->q_aggr.pool != ODP_POOL_INVALID)
destroy_vector_pool(cos_q_param->q_aggr.pool);
}
if (odp_pool_destroy(pool))
ODPH_ERR("err: odp_pool_destroy error\n");
free(args->if_name);
args_error:
ret = odp_term_local();
if (ret)
ODPH_ERR("odp_term_local error %d\n", ret);
ret = odp_term_global(instance);
if (ret)
ODPH_ERR("odp_term_global error %d\n", ret);
printf("Exit\n\n");
return ret;
}
static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len)
{
unsigned i, j;
int dropped = 0;
for (i = 0, j = 0; i < len; ++i) {
pkt = pkt_tbl[i];
odp_packet_free(pkt); /* Drop */
dropped++;
} else if (odp_unlikely(i != j++)) {
pkt_tbl[j-1] = pkt;
}
}
return dropped;
}
static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len)
{
odph_ethhdr_t *eth;
odph_ethaddr_t tmp_addr;
odph_ipv4hdr_t *ip;
odp_u32be_t ip_tmp_addr; /* tmp ip addr */
unsigned i;
for (i = 0; i < len; ++i) {
pkt = pkt_tbl[i];
if (odp_packet_has_eth(pkt)) {
eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL);
tmp_addr = eth->dst;
eth->dst = eth->src;
eth->src = tmp_addr;
if (odp_packet_has_ipv4(pkt)) {
/* IPv4 */
ip = (odph_ipv4hdr_t *)
odp_packet_l3_ptr(pkt, NULL);
ip_tmp_addr = ip->src_addr;
ip->src_addr = ip->dst_addr;
ip->dst_addr = ip_tmp_addr;
}
}
}
}
static int convert_str_to_pmr_enum(char *token, odp_cls_pmr_term_t *term)
{
if (NULL == token)
return -1;
if (strcasecmp(token, "ODP_PMR_ETHTYPE_0") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_ETHTYPE_X") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_VLAN_ID_0") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_VLAN_ID_X") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_UDP_DPORT") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_TCP_DPORT") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_UDP_SPORT") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_TCP_SPORT") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_DIP_ADDR") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_SIP_ADDR") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_DMAC") == 0) {
*term = ODP_PMR_DMAC;
return 0;
} else if (strcasecmp(token, "ODP_PMR_CUSTOM_FRAME") == 0) {
return 0;
} else if (strcasecmp(token, "ODP_PMR_CUSTOM_L3") == 0) {
return 0;
}
return -1;
}
static int parse_pmr_policy(appl_args_t *appl_args, char *optarg)
{
int policy_count;
char *token, *cos0, *cos1, *cur_char;
size_t len;
global_statistics *stats;
odph_ethaddr_t mac;
char *pmr_str;
uint32_t offset, ip_addr, u32;
unsigned long int value, mask;
uint16_t u16;
int val_sz, mask_sz;
policy_count = appl_args->policy_count;
stats = appl_args->stats;
/* last array index is needed for default queue */
if (policy_count >= MAX_PMR_COUNT - 1) {
ODPH_ERR("Too many policies. Max count is %i.\n",
MAX_PMR_COUNT - 1);
return -1;
}
len = strlen(optarg);
len++;
pmr_str = malloc(len);
if (pmr_str == NULL) {
ODPH_ERR("Memory allocation failed\n");
return -1;
}
strcpy(pmr_str, optarg);
/* PMR TERM */
/* <term>:<xxx>:<yyy>:<src_cos>:<dst_cos> */
token = strtok(pmr_str, ":");
if (convert_str_to_pmr_enum(token, &term)) {
ODPH_ERR("Invalid ODP_PMR_TERM string\n");
goto error;
}
stats[policy_count].rule.term = term;
stats[policy_count].rule.offset = 0;
/* PMR value */
switch (term) {
/* Fall through */
/* Fall through */
/* :<type>:<mask> */
/* Fall through */
/* Fall through */
/* :<vlan_id>:<mask> */
/* Fall through */
/* Fall through */
/* Fall through */
/* :<port>:<mask> */
token = strtok(NULL, ":");
odph_strcpy(stats[policy_count].value, token,
DISPLAY_STRING_LEN);
value = strtoul(token, NULL, 0);
u16 = value;
u16 = odp_cpu_to_be_16(u16);
memcpy(stats[policy_count].rule.value_be, &u16, sizeof(u16));
token = strtok(NULL, ":");
odph_strcpy(stats[policy_count].mask, token,
DISPLAY_STRING_LEN);
mask = strtoul(token, NULL, 0);
u16 = mask;
u16 = odp_cpu_to_be_16(u16);
memcpy(stats[policy_count].rule.mask_be, &u16, sizeof(u16));
stats[policy_count].rule.val_sz = 2;
break;
/* Fall through */
/* :<IP addr>:<mask> */
token = strtok(NULL, ":");
odph_strcpy(stats[policy_count].value, token,
DISPLAY_STRING_LEN);
if (odph_ipv4_addr_parse(&ip_addr, token)) {
ODPH_ERR("Bad IP address\n");
goto error;
}
u32 = odp_cpu_to_be_32(ip_addr);
memcpy(stats[policy_count].rule.value_be, &u32, sizeof(u32));
token = strtok(NULL, ":");
odph_strcpy(stats[policy_count].mask, token,
DISPLAY_STRING_LEN);
mask = strtoul(token, NULL, 0);
u32 = mask;
u32 = odp_cpu_to_be_32(u32);
memcpy(stats[policy_count].rule.mask_be, &u32, sizeof(u32));
stats[policy_count].rule.val_sz = 4;
break;
/* :<MAC addr>:<mask> */
token = strtok(NULL, ":");
odph_strcpy(stats[policy_count].value, token,
DISPLAY_STRING_LEN);
/* Replace hyphens in the MAC string with colons to be compatible with
* odph_eth_addr_parse(). */
cur_char = token;
while ((cur_char = strchr(cur_char, '-')) != NULL)
*cur_char++ = ':';
if (odph_eth_addr_parse(&mac, token)) {
ODPH_ERR("Invalid MAC address. Use format 11-22-33-44-55-66.\n");
goto error;
}
memcpy(stats[policy_count].rule.value_be, mac.addr, ODPH_ETHADDR_LEN);
stats[policy_count].rule.val_sz = 6;
token = strtok(NULL, ":");
odph_strcpy(stats[policy_count].mask, token, DISPLAY_STRING_LEN);
mask_sz = parse_custom(token, stats[policy_count].rule.mask_be, ODPH_ETHADDR_LEN);
if (mask_sz != ODPH_ETHADDR_LEN) {
ODPH_ERR("Invalid mask. Provide mask without 0x prefix.\n");
goto error;
}
break;
/* Fall through */
/* :<offset>:<value>:<mask> */
token = strtok(NULL, ":");
errno = 0;
offset = strtoul(token, NULL, 0);
stats[policy_count].rule.offset = offset;
if (errno)
goto error;
token = strtok(NULL, ":");
odph_strcpy(stats[policy_count].value, token,
DISPLAY_STRING_LEN);
val_sz = parse_custom(token,
stats[policy_count].rule.value_be,
MAX_VAL_SIZE);
stats[policy_count].rule.val_sz = val_sz;
if (val_sz <= 0)
goto error;
token = strtok(NULL, ":");
odph_strcpy(stats[policy_count].mask, token,
DISPLAY_STRING_LEN);
mask_sz = parse_custom(token,
stats[policy_count].rule.mask_be,
MAX_VAL_SIZE);
if (mask_sz != val_sz)
goto error;
break;
default:
goto error;
}
/* Optional source CoS name and name of this CoS
* :<src_cos>:<cos> */
cos0 = strtok(NULL, ":");
cos1 = strtok(NULL, ":");
if (cos0 == NULL)
goto error;
if (cos1) {
stats[policy_count].has_src_cos = 1;
odph_strcpy(stats[policy_count].src_cos_name, cos0,
odph_strcpy(stats[policy_count].cos_name, cos1,
} else {
odph_strcpy(stats[policy_count].cos_name, cos0,
}
appl_args->policy_count++;
free(pmr_str);
return 0;
error:
free(pmr_str);
return -1;
}
static int parse_cos_q_param(appl_args_t *appl_args, char *optarg)
{
char *tmp_str = strdup(optarg), *tmp;
cos_q_param_t *cos_q_param;
int ret = 0;
if (tmp_str == NULL)
ODPH_ABORT("Failed to allocate memory, aborting.\n");
if (appl_args->num_cos_q_param >= MAX_PMR_COUNT) {
ODPH_ERR("Too many queue CoS configurations. Max count is %i.\n", MAX_PMR_COUNT);
ret = -1;
goto out;
}
cos_q_param = &appl_args->cos_q_param[appl_args->num_cos_q_param];
cos_q_param->q_aggr.pool = ODP_POOL_INVALID;
tmp = strtok(tmp_str, ":");
if (tmp == NULL) {
ODPH_ERR("CoS queue name missing.\n");
ret = -1;
goto out;
}
if (find_cos_q_param(appl_args, tmp) != NULL) {
printf("Warning: duplicate CoS queue parameter entry for \"%s\", skipping.\n",
tmp);
goto out;
}
odph_strcpy(cos_q_param->cos_name, tmp, ODP_COS_NAME_LEN);
tmp = strtok(NULL, ":");
if (tmp == NULL) {
ODPH_ERR("CoS queue priority missing.\n");
ret = -1;
goto out;
}
cos_q_param->q_prio = strcmp(tmp, "default") == 0 ?
tmp = strtok(NULL, ":");
if (tmp == NULL) {
ODPH_ERR("CoS queue synchronization type missing.\n");
ret = -1;
goto out;
}
if (strcmp(tmp, "ODP_SCHED_SYNC_PARALLEL") == 0) {
cos_q_param->q_sync = ODP_SCHED_SYNC_PARALLEL;
} else if (strcmp(tmp, "ODP_SCHED_SYNC_ATOMIC") == 0) {
cos_q_param->q_sync = ODP_SCHED_SYNC_ATOMIC;
} else if (strcmp(tmp, "ODP_SCHED_SYNC_ORDERED") == 0) {
cos_q_param->q_sync = ODP_SCHED_SYNC_ORDERED;
} else {
ODPH_ERR("Invalid queue synchronization type: \"%s\".\n", tmp);
ret = -1;
goto out;
}
tmp = strtok(NULL, ":");
if (tmp == NULL) {
ODPH_ERR("CoS queue aggregator enqueue profile type missing.\n");
ret = -1;
goto out;
}
if (strcmp(tmp, "ODP_AEP_TYPE_NONE") == 0) {
cos_q_param->cos_enq_prof.type = ODP_AEP_TYPE_NONE;
} else if (strcmp(tmp, "ODP_AEP_TYPE_IPV4_FRAG") == 0) {
cos_q_param->cos_enq_prof.type = ODP_AEP_TYPE_IPV4_FRAG;
} else if (strcmp(tmp, "ODP_AEP_TYPE_IPV6_FRAG") == 0) {
cos_q_param->cos_enq_prof.type = ODP_AEP_TYPE_IPV6_FRAG;
} else if (strcmp(tmp, "ODP_AEP_TYPE_CUSTOM") == 0) {
cos_q_param->cos_enq_prof.type = ODP_AEP_TYPE_CUSTOM;
tmp = strtok(NULL, ":");
if (tmp == NULL) {
ODPH_ERR("Custom aggregator enqueue profile param missing.\n");
ret = -1;
goto out;
}
cos_q_param->cos_enq_prof.param = (uintptr_t)strtoll(tmp, NULL, 16);
} else {
ODPH_ERR("Invalid queue aggregator enqueue profile type: \"%s\".\n", tmp);
ret = -1;
goto out;
}
tmp = strtok(NULL, ":");
if (tmp != NULL) {
cos_q_param->q_aggr.max_tmo_ns = atoll(tmp);
tmp = strtok(NULL, ":");
if (tmp == NULL) {
ODPH_ERR("Malformed aggregator parameter format.\n");
ret = -1;
goto out;
}
cos_q_param->q_aggr.max_size = atoi(tmp);
cos_q_param->q_aggr.event_type = ODP_EVENT_PACKET;
cos_q_param->num_aggr = 1;
}
appl_args->num_cos_q_param++;
appl_args->vector_size = ODPH_MAX(appl_args->vector_size, cos_q_param->q_aggr.max_size);
out:
free(tmp_str);
return ret;
}
static int check_cos_q_param_policies(appl_args_t *appl_args)
{
int j;
for (int i = 0; i < appl_args->num_cos_q_param; i++) {
const char *cq_name = appl_args->cos_q_param[i].cos_name;
for (j = 0; j < appl_args->policy_count; j++) {
if (strcmp(appl_args->stats[j].cos_name, cq_name) == 0)
break;
}
if (j == appl_args->policy_count) {
ODPH_ERR("No matching policy found for cos_queue_param \"%s\"\n", cq_name);
return -1;
}
}
return 0;
}
static int parse_policy_ci_pass_count(appl_args_t *appl_args, char *optarg)
{
int num_ci_pass_rules;
char *token, *value;
size_t len;
ci_pass_counters *ci_pass_rules;
char *count_str;
num_ci_pass_rules = appl_args->num_ci_pass_rules;
ci_pass_rules = appl_args->ci_pass_rules;
/* last array index is needed for default queue */
if (num_ci_pass_rules >= MAX_PMR_COUNT) {
ODPH_ERR("Too many ci pass counters. Max count is %i.\n",
MAX_PMR_COUNT);
return -1;
}
len = strlen(optarg);
len++;
count_str = malloc(len);
if (count_str == NULL) {
ODPH_ERR("Memory allocation failed\n");
return -1;
}
strcpy(count_str, optarg);
token = strtok(count_str, ":");
value = strtok(NULL, ":");
if (!token || !value) {
free(count_str);
return -1;
}
odph_strcpy(ci_pass_rules[num_ci_pass_rules].cos_name, token, ODP_COS_NAME_LEN);
ci_pass_rules[num_ci_pass_rules].count = atoll(value);
appl_args->num_ci_pass_rules++;
free(count_str);
return 0;
}
static int parse_args(int argc, char *argv[], appl_args_t *appl_args)
{
int opt;
size_t len;
int i;
int interface = 0;
int ret = 0;
static const struct option longopts[] = {
{"count", required_argument, NULL, 'c'},
{"interface", required_argument, NULL, 'i'},
{"policy", required_argument, NULL, 'p'},
{"cos_queue_param", required_argument, NULL, 'q'},
{"mode", required_argument, NULL, 'm'},
{"time", required_argument, NULL, 't'},
{"ci_pass", required_argument, NULL, 'C'},
{"promisc_mode", no_argument, NULL, 'P'},
{"verbose", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{"enable", required_argument, NULL, 'e'},
{"layer", required_argument, NULL, 'l'},
{"dedicated", required_argument, NULL, 'd'},
{"size", required_argument, NULL, 's'},
{"burst", required_argument, NULL, 'b'},
{NULL, 0, NULL, 0}
};
static const char *shortopts = "+c:t:i:p:q:m:t:C:Pvhe:l:d:s:b:";
appl_args->cpu_count = 1; /* Use one worker by default */
appl_args->verbose = 0;
appl_args->promisc_mode = 0;
appl_args->classifier_enable = 1;
appl_args->parse_layer = ODP_PROTO_LAYER_ALL;
appl_args->cos_pools = 1;
appl_args->pool_size = SHM_PKT_POOL_SIZE;
appl_args->burst_size = DEF_PKT_BURST;
while (ret == 0) {
opt = getopt_long(argc, argv, shortopts,
longopts, NULL);
if (opt == -1)
break; /* No more options */
switch (opt) {
case 'c':
appl_args->cpu_count = atoi(optarg);
break;
case 'p':
if (parse_pmr_policy(appl_args, optarg)) {
ret = -1;
break;
}
break;
case 'q':
if (parse_cos_q_param(appl_args, optarg)) {
ret = -1;
break;
}
break;
case 't':
appl_args->time = atoi(optarg);
break;
case 'i':
len = strlen(optarg);
if (len == 0) {
ret = -1;
break;
}
len += 1; /* add room for '\0' */
appl_args->if_name = malloc(len);
if (appl_args->if_name == NULL) {
ret = -1;
break;
}
strcpy(appl_args->if_name, optarg);
interface = 1;
break;
case 'm':
i = atoi(optarg);
if (i == 0)
appl_args->appl_mode = APPL_MODE_DROP;
else
appl_args->appl_mode = APPL_MODE_REPLY;
break;
case 'C':
if (parse_policy_ci_pass_count(appl_args, optarg)) {
ret = -1;
break;
}
break;
case 'P':
appl_args->promisc_mode = 1;
break;
case 'v':
appl_args->verbose = 1;
break;
case 'h':
ret = -1;
break;
case 'e':
appl_args->classifier_enable = atoi(optarg);
break;
case 'l':
appl_args->parse_layer = atoi(optarg);
break;
case 'd':
appl_args->cos_pools = atoi(optarg);
break;
case 's':
appl_args->pool_size = atoi(optarg);
break;
case 'b':
appl_args->burst_size = atoi(optarg);
break;
default:
break;
}
}
if (!interface)
ret = -1;
if (appl_args->if_name == NULL)
ret = -1;
if (!ret && check_cos_q_param_policies(appl_args))
ret = -1;
if (ret) {
usage();
free(appl_args->if_name);
}
/* reset optind from the getopt lib */
optind = 1;
return ret;
}
static void print_info(char *progname, appl_args_t *appl_args)
{
printf("Running ODP appl: \"%s\"\n"
"-----------------\n"
"Using IF: %s\n",
progname, appl_args->if_name);
printf("Promisc mode: %s\n", appl_args->promisc_mode ? "enabled" : "disabled");
printf("\n\n");
fflush(NULL);
}
static void usage(void)
{
printf("\n"
"ODP Classifier example.\n"
"Usage: odp_classifier OPTIONS\n"
" E.g. odp_classifier -i eth1 -m 0 -p \"ODP_PMR_SIP_ADDR:10.10.10.0:0xFFFFFF00:queue1\" \\\n"
" -p \"ODP_PMR_SIP_ADDR:10.10.10.10:0xFFFFFFFF:queue1:queue2\" \\\n"
" -q \"queue1:1:ODP_SCHED_SYNC_PARALLEL:ODP_AEP_TYPE_NONE\" \\\n"
" -q \"queue2:3:ODP_SCHED_SYNC_ATOMIC:ODP_AEP_TYPE_CUSTOM:1234:0:4\"\n"
"\n"
"The above example would classify:\n"
" 1) Packets from source IP address 10.10.10.0/24 to queue1, except ...\n"
" 2) Packets from source IP address 10.10.10.10 to queue2\n"
" 3) All other packets to DefaultCos\n"
"\n"
"Mandatory OPTIONS:\n"
" -i, --interface <interface name>\n"
"\n"
"Optional OPTIONS\n"
" -p, --policy <PMR term>:<offset>:<value>:<mask>:<src queue>:<dst queue>\n"
"\n"
" <PMR term> PMR term name defined in odp_cls_pmr_term_t\n"
" <offset> If term is ODP_PMR_CUSTOM_FRAME or _CUSTOM_L3, offset in bytes is used\n"
" <value> PMR value to be matched\n"
" <mask> PMR mask bits to be applied on the PMR value.\n"
" CUSTOM PMR terms accept plain hex string, other PMR terms require\n"
" hex string with '0x' prefix.\n"
" <src queue> Optional name of the source queue (CoS). The default CoS is used when\n"
" this is not defined.\n"
" <dst queue> Name of the destination queue (CoS).\n"
"\n"
" -q, --cos_queue_param <name>:<queue prio>:<queue sync>:<cos enqueue profile type>:<optional custom value>:<optional tmo ns>:<optional size>\n"
"\n"
" <name> Configuration for a queue (CoS) defined with '--policy' 'dst queue'.\n"
" <queue prio> CoS queue priority. Use priority value or \"default\" for default priority.\n"
" <queue sync> CoS queue synchronization. Use ODP_SCHED_SYNC_PARALLEL,\n"
" ODP_SCHED_SYNC_ATOMIC or ODP_SCHED_SYNC_ORDERED.\n"
" <cos enqueue profile type>\n"
" Aggregator enqueue profile type for CoS. Use odp_aggr_enq_profile_t::type\n"
" names.\n"
" <optional custom value>\n"
" If ODP_AEP_TYPE_CUSTOM aggregator enqueue profile was used,\n"
" pass a hex value (without '0x') for odp_aggr_enq_profile_t::param.\n"
" <optional tmo ns>\n"
" Aggregator configuration parameter timeout in nanoseconds. Optional,\n"
" if not passed, aggregation for queue disabled.\n"
" <optional size>\n"
" Aggregator configuration parameter vector size. Mandatory if 'optional tmo ns'\n"
" passed, optional otherwise.\n"
"\n");
printf(" -c, --count <num> CPU count, 0=all available, default=1\n"
"\n"
" -m, --mode <mode> 0: Packet Drop mode. Received packets will be dropped\n"
" !0: Echo mode. Received packets will be sent back\n"
" default: Packet Drop mode\n"
"\n"
" -t, --time <sec> !0: Time for which the classifier will be run in seconds\n"
" 0: Runs in infinite loop\n"
" default: Runs in infinite loop\n"
"\n"
" -e, --enable <enable> 0: Classifier is disabled\n"
" 1: Classifier is enabled\n"
" default: Classifier is enabled\n"
"\n"
" -l, --layer <layer> Parse packets up to and including this layer. See odp_proto_layer_t\n"
" default: ODP_PROTO_LAYER_ALL\n"
"\n"
" -d, --dedicated <enable> 0: One pool for pktio and all CoSes\n"
" 1: Dedicated pools for pktio and each CoS\n"
" default: Dedicated pools\n"
"\n"
" -s, --size <num> Number of packets in each packet pool\n"
" default: %d\n"
"\n"
" -b, --burst <num> Packet burst size\n"
" default: %d\n"
"\n"
" -C, --ci_pass <dst queue:count>\n"
" Minimum acceptable packet count for a CoS destination queue.\n"
" If the received packet count is smaller than this value,\n"
" the application will exit with an error.\n"
" E.g: -C \"queue1:100\" -C \"queue2:200\" -C \"DefaultQueue:100\"\n"
" -P, --promisc_mode Enable promiscuous mode.\n"
" -v, --verbose Verbose output.\n"
" -h, --help Display help and exit.\n"
"\n", SHM_PKT_POOL_SIZE, DEF_PKT_BURST);
}
void odp_atomic_init_u64(odp_atomic_u64_t *atom, uint64_t val)
Initialize atomic uint64 variable.
void odp_atomic_inc_u64(odp_atomic_u64_t *atom)
Increment atomic uint64 variable.
void odp_atomic_add_u64(odp_atomic_u64_t *atom, uint64_t val)
Add to atomic uint64 variable.
uint64_t odp_atomic_load_u64(odp_atomic_u64_t *atom)
Load value of atomic uint64 variable.
#define ODP_COS_NAME_LEN
Maximum class of service name length, including the null character.
int odp_cos_destroy(odp_cos_t cos)
Discard a class-of-service along with all its associated resources.
odp_pmr_t odp_cls_pmr_create(const odp_pmr_param_t *terms, int num_terms, odp_cos_t src_cos, odp_cos_t dst_cos)
Create Packet Matching Rule (PMR)
odp_cls_pmr_term_t
Packet Matching Rule terms.
#define ODP_PMR_INVALID
Invalid packet matching rule handle.
void odp_cls_print_all(void)
Print classifier info.
int odp_cls_pmr_destroy(odp_pmr_t pmr)
Function to destroy a packet match rule.
#define ODP_COS_INVALID
Invalid class of service handle.
odp_cos_t odp_cls_cos_create(const char *name, const odp_cls_cos_param_t *param)
Create a class-of-service.
void odp_cls_cos_param_init(odp_cls_cos_param_t *param)
Initialize class of service parameters.
void odp_cls_pmr_param_init(odp_pmr_param_t *param)
Initialize packet matching rule parameters.
@ ODP_PMR_TCP_DPORT
Destination TCP port (val_sz = 2)
@ ODP_PMR_ETHTYPE_0
Initial (outer) Ethertype only (val_sz = 2)
@ ODP_PMR_SIP_ADDR
Source IPv4 address (val_sz = 4)
@ ODP_PMR_DIP_ADDR
Destination IPv4 address (val_sz = 4)
@ ODP_PMR_TCP_SPORT
Source TCP port (val_sz = 2)
@ ODP_PMR_VLAN_ID_X
Last (most inner) VLAN ID (val_sz = 2)
@ ODP_PMR_CUSTOM_FRAME
Custom frame match rule.
@ ODP_PMR_UDP_SPORT
Source UDP port (val_sz = 2)
@ ODP_PMR_VLAN_ID_0
First (outer) VLAN ID (val_sz = 2)
@ ODP_PMR_UDP_DPORT
Destination UDP port (val_sz = 2)
@ ODP_PMR_DMAC
Destination MAC address (val_sz = 6)
@ ODP_PMR_ETHTYPE_X
Ethertype of most inner VLAN tag (val_sz = 2)
@ ODP_PMR_CUSTOM_L3
Custom layer 3 match rule.
#define odp_unlikely(x)
Branch unlikely taken.
Definition: spec/hints.h:64
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.
odp_u32be_t odp_cpu_to_be_32(uint32_t cpu32)
Convert cpu native uint32_t to 32bit big endian.
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.
int32_t odp_cpumask_to_str(const odp_cpumask_t *mask, char *str, int32_t size)
Format a string from CPU mask.
#define ODP_CPUMASK_STR_SIZE
The maximum number of characters needed to record any CPU mask as a string (output of odp_cpumask_to_...
void odp_event_vector_free(odp_event_vector_t evv)
Free event vector.
odp_event_vector_t odp_event_vector_from_event(odp_event_t ev)
Get event vector handle from event.
uint32_t odp_event_vector_tbl(odp_event_vector_t evv, odp_event_t **event_tbl)
Get event vector table.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an 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_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_promisc_mode(odp_pktio_t pktio)
Determine if promiscuous mode is enabled for a packet IO interface.
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.
int odp_pktio_promisc_mode_set(odp_pktio_t pktio, odp_bool_t enable)
Set promiscuous mode.
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.
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_pktio_capability(odp_pktio_t pktio, odp_pktio_capability_t *capa)
Query packet IO interface capabilities.
int odp_pktout_send(odp_pktout_queue_t queue, const odp_packet_t packets[], int num)
Send packets directly to an interface output queue.
uint64_t odp_pktio_to_u64(odp_pktio_t pktio)
Get printable value for an odp_pktio_t.
int odp_pktio_default_cos_set(odp_pktio_t pktio, odp_cos_t default_cos)
Setup per-port default class-of-service.
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_SCHED
Packet input through scheduler and scheduled event queues.
void odp_packet_print_data(odp_packet_t pkt, uint32_t offset, uint32_t len)
Print packet data.
void odp_packet_from_event_multi(odp_packet_t pkt[], const odp_event_t ev[], int num)
Convert multiple packet events to packet handles.
int odp_packet_has_ipv4(odp_packet_t pkt)
Check for IPv4.
int odp_packet_has_eth(odp_packet_t pkt)
Check for Ethernet header.
uint32_t odp_packet_len(odp_packet_t pkt)
Packet data length.
int odp_packet_has_error(odp_packet_t pkt)
Check for all parse errors in packet.
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_l2_ptr(odp_packet_t pkt, uint32_t *len)
Layer 2 start pointer.
void * odp_packet_l3_ptr(odp_packet_t pkt, uint32_t *len)
Layer 3 start pointer.
void odp_packet_free_multi(const odp_packet_t pkt[], int num)
Free multiple packets.
odp_pool_t odp_packet_pool(odp_packet_t pkt)
Packet pool.
@ ODP_PROTO_LAYER_ALL
All layers.
uint64_t odp_pool_to_u64(odp_pool_t hdl)
Get printable value for an odp_pool_t.
#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()
void odp_pool_print_all(void)
Print debug info about all pools.
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_PACKET
Packet pool.
@ ODP_POOL_EVENT_VECTOR
Event vector pool.
odp_queue_t odp_queue_aggr(odp_queue_t queue, uint32_t aggr_index)
Get a queue handle of an event aggregator associated with a queue.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#define ODP_QUEUE_INVALID
Invalid queue.
void odp_queue_print_all(void)
Print debug info about all queues.
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_info(odp_queue_t queue, odp_queue_info_t *info)
Retrieve information about a queue.
@ ODP_QUEUE_TYPE_SCHED
Scheduled queue.
int odp_schedule_sync_t
Scheduler synchronization method.
#define ODP_SCHED_SYNC_PARALLEL
Parallel scheduled queues.
int odp_schedule_prio_t
Scheduling priority level.
int odp_schedule_multi(odp_queue_t *from, uint64_t wait, odp_event_t events[], int num)
Schedule multiple events.
#define ODP_SCHED_SYNC_ATOMIC
Atomic queue synchronization.
#define ODP_SCHED_SYNC_ORDERED
Ordered queue synchronization.
int odp_schedule_default_prio(void)
Default scheduling priority level.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
uint64_t odp_schedule_wait_time(uint64_t ns)
Schedule wait time.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
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.
bool odp_bool_t
Boolean type.
void odp_sys_info_print(void)
Print system info.
int odp_thread_id(void)
Get thread identifier.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
odp_time_t odp_time_local(void)
Current local time.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1)
Time difference in nanoseconds.
The OpenDataPlane API.
Dummy type for strong typing.
Event aggregator enqueuing profile.
Class of service parameters Used to communicate class of service creation options.
odp_queue_t queue
Mapping used when num_queue = 1, hashing is disabled in this case and application has to configure th...
odp_aggr_enq_profile_t aggr_enq_profile
Event aggregator enqueuing profile.
odp_pool_t pool
Pool associated with CoS.
Event vector configuration.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
Packet input queue parameters.
odp_bool_t classifier_enable
Enable classifier.
odp_pktio_set_op_t set_op
Supported set operations.
uint32_t max_output_queues
Maximum number of output queues.
Packet IO configuration options.
odp_pktio_parser_config_t parser
Packet input parser configuration.
Packet IO parameters.
odp_pktin_mode_t in_mode
Packet input mode.
odp_proto_layer_t layer
Protocol parsing level in packet input.
Packet output queue parameters.
uint32_t num_queues
Number of output queues to be created.
Packet Matching Rule parameter structure.
uint32_t offset
Offset to the value.
uint32_t val_sz
Size of the value to be matched.
struct odp_pmr_param_t::@4::@6 match
Parameters for single-valued matches.
odp_cls_pmr_term_t term
Packet Matching Rule term.
Pool parameters.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@141 event_vector
Parameters for event vector pools.
struct odp_pool_param_t::@138 pkt
Parameters for packet pools.
odp_pool_type_t type
Pool type.
uint32_t len
Minimum length of 'num' packets.
uint32_t max_size
Maximum number of handles (such as odp_packet_t) in a vector.
uint32_t seg_len
Minimum number of packet data bytes that can be stored in the first segment of a newly allocated pack...
Queue information.
const char * name
Queue name.
ODP Queue parameters.
odp_schedule_param_t sched
Scheduler parameters.
odp_queue_type_t type
Queue type.
const odp_event_aggr_config_t * aggr
Event aggregator configuration parameters.
uint32_t num_aggr
Number of event aggregators.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.
struct odp_pktio_set_op_t::@111 op
Operation flags.
uint32_t promisc_mode
Promiscuous mode.