API Reference Manual  1.46.0
odp_classifier.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2015-2018 Linaro Limited
3  * Copyright (c) 2019-2022 Nokia
4  * Copyright (c) 2020 Marvell
5  */
6 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <getopt.h>
18 #include <unistd.h>
19 #include <inttypes.h>
20 #include <signal.h>
21 
22 #include <odp_api.h>
23 #include <odp/helper/odph_api.h>
24 
25 #include <strings.h>
26 #include <errno.h>
27 #include <stdio.h>
28 
32 #define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
33 
37 #define MAX_PKT_BURST 64
38 
42 #define DEF_PKT_BURST 32
43 
47 #define SHM_PKT_POOL_SIZE 10000
48 
52 #define SHM_PKT_POOL_BUF_SIZE 1856
53 
57 #define MAX_PMR_COUNT 32
58 
62 #define DISPLAY_STRING_LEN 32
63 
65 #define MAX_VAL_SIZE 16
66 
68 #define NO_PATH(file_name) (strrchr((file_name), '/') ? \
69  strrchr((file_name), '/') + 1 : (file_name))
70 
71 typedef struct {
72  odp_queue_t queue;
73  odp_pool_t pool;
74  odp_cos_t cos;
75  odp_pmr_t pmr;
76  odp_atomic_u64_t queue_pkt_count;
77  odp_atomic_u64_t pool_pkt_count;
78  char cos_name[ODP_COS_NAME_LEN];
79  char src_cos_name[ODP_COS_NAME_LEN];
80  struct {
81  odp_cls_pmr_term_t term;
82  uint8_t value_be[MAX_VAL_SIZE];
83  uint8_t mask_be[MAX_VAL_SIZE];
84  uint32_t val_sz;
85  uint32_t offset;
86  } rule;
87  char value[DISPLAY_STRING_LEN];
88  char mask[DISPLAY_STRING_LEN];
89  int has_src_cos;
90 
91 } global_statistics;
92 
93 typedef struct {
94  char cos_name[ODP_COS_NAME_LEN];
95  uint64_t count;
96 } ci_pass_counters;
97 
98 typedef struct {
99  odp_pktout_queue_t pktout[MAX_WORKERS];
100  int num_pktout;
101  global_statistics stats[MAX_PMR_COUNT];
102  ci_pass_counters ci_pass_rules[MAX_PMR_COUNT];
103  int policy_count;
104  int num_ci_pass_rules;
105  int appl_mode;
106  odp_atomic_u64_t total_packets;
107  unsigned int cpu_count;
108  uint32_t time;
109  char *if_name;
110  int shutdown;
111  int shutdown_sig;
112  int verbose;
113  int promisc_mode;
114  int classifier_enable;
115  int parse_layer;
116  int cos_pools;
117  int pool_size;
118  int burst_size;
119 } appl_args_t;
120 
121 enum packet_mode {
122  APPL_MODE_DROP,
123  APPL_MODE_REPLY
124 };
125 
126 static appl_args_t *appl_args_gbl;
127 
128 static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len);
129 static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len);
130 static int parse_args(int argc, char *argv[], appl_args_t *appl_args);
131 static void print_info(char *progname, appl_args_t *appl_args);
132 static void usage(void);
133 
134 static inline int check_ci_pass_count(appl_args_t *args)
135 {
136  int i, j;
137  uint64_t count;
138 
139  if (args->num_ci_pass_rules == 0)
140  return 0;
141 
142  for (i = 0; i < args->num_ci_pass_rules; i++) {
143  for (j = 0; j < args->policy_count; j++) {
144  if (!strcmp(args->stats[j].cos_name,
145  args->ci_pass_rules[i].cos_name)) {
146  count = odp_atomic_load_u64(&args->stats[i].queue_pkt_count);
147  if (args->ci_pass_rules[i].count > count) {
148  ODPH_ERR("Error: Cos = %s, expected packets = %" PRIu64 ","
149  "received packet = %" PRIu64 "\n",
150  args->stats[j].cos_name,
151  args->ci_pass_rules[i].count, count);
152  return -1;
153  }
154  break;
155  }
156  }
157  if (j == args->policy_count) {
158  ODPH_ERR("Error: invalid Cos:%s specified for CI pass count\n",
159  args->ci_pass_rules[i].cos_name);
160  return -1;
161  }
162  }
163  return 0;
164 }
165 
166 static inline void print_cls_statistics(appl_args_t *args)
167 {
168  int i;
169  uint32_t timeout;
170  int infinite = 0;
171 
172  printf("\n");
173  for (i = 0; i < 40; i++)
174  printf("-");
175  printf("\n");
176  /* print statistics */
177  printf("CLASSIFIER EXAMPLE STATISTICS\n");
178  for (i = 0; i < 40; i++)
179  printf("-");
180  printf("\n");
181  printf("CONFIGURATION\n");
182  printf("\n");
183  printf("COS\tVALUE\t\tMASK\n");
184  for (i = 0; i < 40; i++)
185  printf("-");
186  printf("\n");
187  for (i = 0; i < args->policy_count - 1; i++) {
188  printf("%s\t", args->stats[i].cos_name);
189  printf("%s\t", args->stats[i].value);
190  printf("%s\n", args->stats[i].mask);
191  }
192  printf("\n");
193  printf("RECEIVED PACKETS\n");
194  for (i = 0; i < 40; i++)
195  printf("-");
196  printf("\n");
197  for (i = 0; i < args->policy_count; i++)
198  printf("%-12s |", args->stats[i].cos_name);
199  printf("%-6s %-6s", "Total", "Mpps");
200  printf("\n");
201  for (i = 0; i < args->policy_count; i++)
202  printf("%-6s %-6s|", "queue", "pool");
203  printf("\n");
204 
205  timeout = args->time;
206 
207  /* Incase if default value is given for timeout
208  run the loop infinitely */
209  if (timeout == 0)
210  infinite = 1;
211 
212  uint64_t total_packets, last_total_packets = 0;
213  odp_time_t start = odp_time_local(), end;
214  float mpps;
215 
216  for (; timeout > 0 || infinite; timeout--) {
217  sleep(1);
218  for (i = 0; i < args->policy_count; i++) {
219  printf("%-6" PRIu64 " ",
220  odp_atomic_load_u64(&args->stats[i]
221  .queue_pkt_count));
222  printf("%-6" PRIu64 "|",
223  odp_atomic_load_u64(&args->stats[i]
224  .pool_pkt_count));
225  }
226 
227  end = odp_time_local();
228  total_packets = odp_atomic_load_u64(&args->total_packets);
229  mpps = (total_packets - last_total_packets) /
230  (odp_time_diff_ns(end, start) / 1000.0);
231  printf("%-6" PRIu64 " %-6.3f\n", total_packets, mpps);
232  last_total_packets = total_packets;
233  start = end;
234 
235  if (args->shutdown_sig)
236  break;
237  }
238 
239  printf("\n");
240 }
241 
242 static int parse_custom(const char *str, uint8_t *buf_be, int max_size)
243 {
244  int i, len;
245 
246  /* hex string without 0x prefix */
247  len = strlen(str);
248  if (len > 2 * max_size)
249  return -1;
250 
251  for (i = 0; i < len; i += 2)
252  if (sscanf(&str[i], "%2" SCNx8, &buf_be[i / 2]) != 1)
253  return -1;
254 
255  return len / 2;
256 }
257 
267 static odp_pktio_t create_pktio(const char *dev, odp_pool_t pool)
268 {
269  odp_pktio_t pktio;
270  odp_pktio_param_t pktio_param;
271  odp_pktin_queue_param_t pktin_param;
273  odp_pktio_config_t cfg;
274  odp_pktout_queue_param_t pktout_queue_param;
275  int num_tx;
276 
277  odp_pktio_param_init(&pktio_param);
278  pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
279 
280  /* Open a packet IO instance */
281  pktio = odp_pktio_open(dev, pool, &pktio_param);
282  if (pktio == ODP_PKTIO_INVALID) {
283  ODPH_ERR("pktio create failed for %s\n", dev);
284  exit(EXIT_FAILURE);
285  }
286 
287  if (odp_pktio_capability(pktio, &capa)) {
288  ODPH_ERR("pktio capability failed for %s\n", dev);
289  exit(EXIT_FAILURE);
290  }
291 
292  odp_pktin_queue_param_init(&pktin_param);
293  pktin_param.classifier_enable = appl_args_gbl->classifier_enable;
294 
295  if (odp_pktin_queue_config(pktio, &pktin_param)) {
296  ODPH_ERR("pktin queue config failed for %s\n", dev);
297  exit(EXIT_FAILURE);
298  }
299 
300  num_tx = appl_args_gbl->cpu_count;
301 
302  if (num_tx > (int)capa.max_output_queues) {
303  printf("Sharing %i output queues between %i workers\n",
304  capa.max_output_queues, num_tx);
305  num_tx = capa.max_output_queues;
306  }
307 
308  appl_args_gbl->num_pktout = num_tx;
309 
310  odp_pktout_queue_param_init(&pktout_queue_param);
311  pktout_queue_param.num_queues = num_tx;
312 
313  if (odp_pktout_queue_config(pktio, &pktout_queue_param)) {
314  ODPH_ERR("pktout queue config failed for %s\n", dev);
315  exit(EXIT_FAILURE);
316  }
317 
318  if (odp_pktout_queue(pktio, appl_args_gbl->pktout, num_tx) != num_tx) {
319  ODPH_ERR("Pktout queue query failed: %s\n", dev);
320  exit(EXIT_FAILURE);
321  }
322 
323  if (appl_args_gbl->promisc_mode && odp_pktio_promisc_mode(pktio) != 1) {
324  if (!capa.set_op.op.promisc_mode) {
325  ODPH_ERR("enabling promisc mode not supported %s\n", dev);
326  exit(EXIT_FAILURE);
327  }
328 
329  if (odp_pktio_promisc_mode_set(pktio, true)) {
330  ODPH_ERR("failed to enable promisc mode for %s\n", dev);
331  exit(EXIT_FAILURE);
332  }
333  }
334 
335  printf("created pktio:%" PRIu64 ", dev:%s", odp_pktio_to_u64(pktio), dev);
336 
337  odph_ethaddr_t mac;
338 
339  if (odp_pktio_mac_addr(pktio, &mac, sizeof(mac)) == sizeof(mac)) {
340  printf(", mac");
341  for (int c = 0; c < (int)sizeof(mac); c++)
342  printf(":%02x", mac.addr[c]);
343  }
344 
345  printf("\n");
346 
347  odp_pktio_config_init(&cfg);
348  cfg.parser.layer = appl_args_gbl->parse_layer;
349  if (odp_pktio_config(pktio, &cfg)) {
350  ODPH_ERR("failed to configure pktio %s\n", dev);
351  exit(EXIT_FAILURE);
352  }
353 
354  return pktio;
355 }
356 
361 static int pktio_receive_thread(void *arg)
362 {
363  int thr;
364  odp_packet_t pkt[MAX_PKT_BURST];
365  odp_pool_t pool;
366  odp_event_t ev[MAX_PKT_BURST];
367  odp_queue_t queue;
368  int i, j, num, dropped, sent;
369  global_statistics *stats;
370  unsigned long err_cnt = 0;
371  thr = odp_thread_id();
372  appl_args_t *appl = (appl_args_t *)arg;
373  uint64_t wait_time = odp_schedule_wait_time(100 * ODP_TIME_MSEC_IN_NS);
374  odp_pktout_queue_t pktout = appl_args_gbl->pktout[thr % appl_args_gbl->num_pktout];
375 
376  /* Loop packets */
377  for (;;) {
378  if (appl->shutdown)
379  break;
380 
381  /* Use schedule to get buf from any input queue */
382  num = odp_schedule_multi(&queue, wait_time, ev, appl_args_gbl->burst_size);
383 
384  /* Loop back to receive packets incase of invalid event */
385  if (odp_unlikely(!num))
386  continue;
387 
388  odp_packet_from_event_multi(pkt, ev, num);
389 
390  if (odp_unlikely(appl->verbose)) {
391  for (j = 0; j < num; j++) {
392  odp_queue_info_t info;
393  uint32_t len = odp_packet_len(pkt[j]);
394 
395  if (odp_queue_info(queue, &info) == 0)
396  printf("Queue: %s\n", info.name);
397 
398  if (len > 96)
399  len = 96;
400 
401  odp_packet_print_data(pkt[j], 0, len);
402  }
403  }
404 
405  /* Total packets received */
406  odp_atomic_add_u64(&appl->total_packets, num);
407 
408  /* Drop packets with errors */
409  dropped = drop_err_pkts(pkt, num);
410  if (odp_unlikely(dropped)) {
411  num -= dropped;
412  err_cnt += dropped;
413  ODPH_ERR("Drop frame - err_cnt:%lu\n", err_cnt);
414  }
415 
416  for (j = 0; j < num; j++) {
417  pool = odp_packet_pool(pkt[j]);
418 
419  for (i = 0; i < MAX_PMR_COUNT; i++) {
420  stats = &appl->stats[i];
421  if (queue == stats->queue)
422  odp_atomic_inc_u64(&stats->queue_pkt_count);
423  if (pool == stats->pool)
424  odp_atomic_inc_u64(&stats->pool_pkt_count);
425  }
426  }
427 
428  if (appl->appl_mode == APPL_MODE_DROP) {
429  odp_packet_free_multi(pkt, num);
430  continue;
431  }
432 
433  /* Swap Eth MACs and possibly IP-addrs before sending back */
434  swap_pkt_addrs(pkt, num);
435 
436  sent = odp_pktout_send(pktout, pkt, num);
437  sent = sent < 0 ? 0 : sent;
438 
439  if (sent != num) {
440  ODPH_ERR(" [%i] Packet send failed\n", thr);
441  odp_packet_free_multi(pkt + sent, num - sent);
442  }
443  }
444 
445  return 0;
446 }
447 
448 static odp_pool_t pool_create(const char *name)
449 {
450  static odp_pool_t pool = ODP_POOL_INVALID;
451  odp_pool_param_t pool_params;
452 
453  if (!appl_args_gbl->cos_pools && pool != ODP_POOL_INVALID)
454  return pool;
455 
456  odp_pool_param_init(&pool_params);
457  pool_params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
458  pool_params.pkt.len = SHM_PKT_POOL_BUF_SIZE;
459  pool_params.pkt.num = appl_args_gbl->pool_size;
460  pool_params.type = ODP_POOL_PACKET;
461  pool = odp_pool_create(name, &pool_params);
462 
463  if (pool == ODP_POOL_INVALID) {
464  ODPH_ERR("Error: failed to create pool %s\n", name);
465  exit(EXIT_FAILURE);
466  }
467 
468  return pool;
469 }
470 
471 static odp_cos_t configure_default_cos(odp_pktio_t pktio, appl_args_t *args)
472 {
473  odp_queue_param_t qparam;
474  const char *queue_name = "DefaultQueue";
475  const char *pool_name = "DefaultPool";
476  const char *cos_name = "DefaultCos";
477  odp_queue_t queue_default;
478  odp_pool_t pool_default;
479  odp_cos_t cos_default;
480  odp_cls_cos_param_t cls_param;
481  global_statistics *stats = args->stats;
482 
483 
484  odp_queue_param_init(&qparam);
485  qparam.type = ODP_QUEUE_TYPE_SCHED;
488  queue_default = odp_queue_create(queue_name, &qparam);
489  if (queue_default == ODP_QUEUE_INVALID) {
490  ODPH_ERR("Error: default queue create failed\n");
491  exit(EXIT_FAILURE);
492  }
493 
494  pool_default = pool_create(pool_name);
495 
496  odp_cls_cos_param_init(&cls_param);
497  cls_param.pool = pool_default;
498  cls_param.queue = queue_default;
499 
500  cos_default = odp_cls_cos_create(cos_name, &cls_param);
501 
502  if (cos_default == ODP_COS_INVALID) {
503  ODPH_ERR("Error: default cos create failed\n");
504  exit(EXIT_FAILURE);
505  }
506 
507  if (0 > odp_pktio_default_cos_set(pktio, cos_default)) {
508  ODPH_ERR("odp_pktio_default_cos_set failed\n");
509  exit(EXIT_FAILURE);
510  }
511  stats[args->policy_count].cos = cos_default;
512  /* add default queue to global stats */
513  stats[args->policy_count].queue = queue_default;
514  if (appl_args_gbl->cos_pools)
515  stats[args->policy_count].pool = pool_default;
516  snprintf(stats[args->policy_count].cos_name,
517  sizeof(stats[args->policy_count].cos_name),
518  "%s", cos_name);
519  odp_atomic_init_u64(&stats[args->policy_count].queue_pkt_count, 0);
520  odp_atomic_init_u64(&stats[args->policy_count].pool_pkt_count, 0);
521  args->policy_count++;
522  return cos_default;
523 }
524 
525 static int find_cos(appl_args_t *args, const char *name, odp_cos_t *cos)
526 {
527  global_statistics *stats;
528  int i;
529 
530  for (i = 0; i < args->policy_count - 1; i++) {
531  stats = &args->stats[i];
532 
533  if (strcmp(stats->cos_name, name) == 0) {
534  *cos = stats->cos;
535  return 0;
536  }
537  }
538 
539  return -1;
540 }
541 
542 static void configure_cos(odp_cos_t default_cos, appl_args_t *args)
543 {
544  char cos_name[ODP_COS_NAME_LEN];
545  char pool_name[ODP_POOL_NAME_LEN];
546  const char *queue_name;
547  odp_cls_cos_param_t cls_param;
548  int i;
549  global_statistics *stats;
550  odp_queue_param_t qparam;
551 
552  for (i = 0; i < args->policy_count - 1; i++) {
553  stats = &args->stats[i];
554 
555  odp_queue_param_init(&qparam);
556  qparam.type = ODP_QUEUE_TYPE_SCHED;
559 
560  queue_name = args->stats[i].cos_name;
561  stats->queue = odp_queue_create(queue_name, &qparam);
562  if (ODP_QUEUE_INVALID == stats->queue) {
563  ODPH_ERR("odp_queue_create failed\n");
564  exit(EXIT_FAILURE);
565  }
566 
567  snprintf(pool_name, sizeof(pool_name), "%sPool%d",
568  args->stats[i].cos_name, i);
569 
570  snprintf(cos_name, sizeof(cos_name), "CoS%s",
571  stats->cos_name);
572  odp_cls_cos_param_init(&cls_param);
573  cls_param.pool = pool_create(pool_name);
574  if (appl_args_gbl->cos_pools)
575  stats->pool = cls_param.pool;
576  cls_param.queue = stats->queue;
577 
578  stats->cos = odp_cls_cos_create(cos_name, &cls_param);
579 
580  odp_atomic_init_u64(&stats->queue_pkt_count, 0);
581  odp_atomic_init_u64(&stats->pool_pkt_count, 0);
582  }
583 
584  for (i = 0; i < args->policy_count - 1; i++) {
585  odp_pmr_param_t pmr_param;
586  odp_cos_t src_cos = default_cos;
587 
588  stats = &args->stats[i];
589 
590  if (stats->has_src_cos) {
591  if (find_cos(args, stats->src_cos_name, &src_cos)) {
592  ODPH_ERR("find_cos failed\n");
593  exit(EXIT_FAILURE);
594  }
595  }
596 
597  odp_cls_pmr_param_init(&pmr_param);
598  pmr_param.term = stats->rule.term;
599  pmr_param.match.value = stats->rule.value_be;
600  pmr_param.match.mask = stats->rule.mask_be;
601  pmr_param.val_sz = stats->rule.val_sz;
602  pmr_param.offset = stats->rule.offset;
603 
604  stats->pmr = odp_cls_pmr_create(&pmr_param, 1, src_cos,
605  stats->cos);
606  if (stats->pmr == ODP_PMR_INVALID) {
607  ODPH_ERR("odp_pktio_pmr_cos failed\n");
608  exit(EXIT_FAILURE);
609  }
610  }
611 
612 }
613 
614 static void sig_handler(int signo)
615 {
616  (void)signo;
617 
618  if (appl_args_gbl == NULL)
619  return;
620  appl_args_gbl->shutdown_sig = 1;
621 }
622 
626 int main(int argc, char *argv[])
627 {
628  odph_helper_options_t helper_options;
629  odph_thread_t thread_tbl[MAX_WORKERS];
630  odp_pool_t pool;
631  int num_workers;
632  int i;
633  odp_cpumask_t cpumask;
634  char cpumaskstr[ODP_CPUMASK_STR_SIZE];
635  odp_pktio_t pktio;
636  appl_args_t *args;
637  odp_cos_t default_cos;
638  odp_shm_t shm;
639  int ret;
640  odp_instance_t instance;
641  odp_init_t init_param;
642  odph_thread_common_param_t thr_common;
643  odph_thread_param_t thr_param;
644 
645  signal(SIGINT, sig_handler);
646 
647  /* Let helper collect its own arguments (e.g. --odph_proc) */
648  argc = odph_parse_options(argc, argv);
649  if (odph_options(&helper_options)) {
650  ODPH_ERR("Error: reading ODP helper options failed\n");
651  exit(EXIT_FAILURE);
652  }
653 
654  odp_init_param_init(&init_param);
655  init_param.mem_model = helper_options.mem_model;
656 
657  /* Init ODP before calling anything else */
658  if (odp_init_global(&instance, &init_param, NULL)) {
659  ODPH_ERR("Error: ODP global init failed\n");
660  exit(EXIT_FAILURE);
661  }
662 
663  /* Init this thread */
664  if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
665  ODPH_ERR("Error: ODP local init failed\n");
666  exit(EXIT_FAILURE);
667  }
668 
669  /* Reserve memory for args from shared mem */
670  shm = odp_shm_reserve("cls_shm_args", sizeof(appl_args_t),
671  ODP_CACHE_LINE_SIZE, 0);
672 
673  if (shm == ODP_SHM_INVALID) {
674  ODPH_ERR("Error: shared mem reserve failed\n");
675  exit(EXIT_FAILURE);
676  }
677 
678  args = odp_shm_addr(shm);
679 
680  if (args == NULL) {
681  ODPH_ERR("Error: shared mem alloc failed\n");
682  exit(EXIT_FAILURE);
683  }
684 
685  appl_args_gbl = args;
686  memset(args, 0, sizeof(*args));
687  /* Parse and store the application arguments */
688  if (parse_args(argc, argv, args))
689  goto args_error;
690 
691  /* Print both system and application information */
692  print_info(NO_PATH(argv[0]), args);
693 
694  num_workers = MAX_WORKERS;
695  if (args->cpu_count && args->cpu_count < MAX_WORKERS)
696  num_workers = args->cpu_count;
697 
698  /* Get default worker cpumask */
699  num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
700  (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
701 
702  printf("num worker threads: %i\n", num_workers);
703  printf("first CPU: %i\n", odp_cpumask_first(&cpumask));
704  printf("cpu mask: %s\n", cpumaskstr);
705 
706  /* Create packet pool */
707  pool = pool_create("packet_pool");
708 
709  /* Configure scheduler */
710  odp_schedule_config(NULL);
711 
712  /* odp_pool_print(pool); */
713  odp_atomic_init_u64(&args->total_packets, 0);
714 
715  /* create pktio per interface */
716  pktio = create_pktio(args->if_name, pool);
717 
718  /* configure default Cos */
719  default_cos = configure_default_cos(pktio, args);
720 
721  configure_cos(default_cos, args);
722 
723  printf("\n");
726 
727  if (odp_pktio_start(pktio)) {
728  ODPH_ERR("Error: unable to start pktio\n");
729  exit(EXIT_FAILURE);
730  }
731 
732  /* Create and init worker threads */
733  memset(thread_tbl, 0, sizeof(thread_tbl));
734  odph_thread_common_param_init(&thr_common);
735  odph_thread_param_init(&thr_param);
736 
737  thr_param.start = pktio_receive_thread;
738  thr_param.arg = args;
739  thr_param.thr_type = ODP_THREAD_WORKER;
740 
741  thr_common.instance = instance;
742  thr_common.cpumask = &cpumask;
743  thr_common.share_param = 1;
744 
745  odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers);
746 
747  if (args->verbose == 0) {
748  print_cls_statistics(args);
749  } else {
750  int timeout = args->time;
751 
752  for (i = 0; timeout == 0 || i < timeout; i++) {
753  if (args->shutdown_sig)
754  break;
755 
756  sleep(1);
757  }
758  }
759 
760  odp_pktio_stop(pktio);
761  args->shutdown = 1;
762  odph_thread_join(thread_tbl, num_workers);
763 
764  if (check_ci_pass_count(args)) {
765  ODPH_ERR("Error: Packet count verification failed\n");
766  exit(EXIT_FAILURE);
767  }
768 
769  for (i = 0; i < args->policy_count; i++) {
770  if ((i != args->policy_count - 1) &&
771  odp_cls_pmr_destroy(args->stats[i].pmr))
772  ODPH_ERR("err: odp_cls_pmr_destroy for %d\n", i);
773  if (odp_cos_destroy(args->stats[i].cos))
774  ODPH_ERR("err: odp_cos_destroy for %d\n", i);
775  if (odp_queue_destroy(args->stats[i].queue))
776  ODPH_ERR("err: odp_queue_destroy for %d\n", i);
777  if (args->cos_pools && odp_pool_destroy(args->stats[i].pool))
778  ODPH_ERR("err: odp_pool_destroy for %d\n", i);
779  }
780 
781  if (odp_pktio_close(pktio))
782  ODPH_ERR("err: close pktio error\n");
783  if (odp_pool_destroy(pool))
784  ODPH_ERR("err: odp_pool_destroy error\n");
785 
786  free(args->if_name);
787 
788 args_error:
789  odp_shm_free(shm);
790 
791  ret = odp_term_local();
792  if (ret)
793  ODPH_ERR("odp_term_local error %d\n", ret);
794  ret = odp_term_global(instance);
795  if (ret)
796  ODPH_ERR("odp_term_global error %d\n", ret);
797  printf("Exit\n\n");
798  return ret;
799 }
800 
812 static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len)
813 {
814  odp_packet_t pkt;
815  unsigned i, j;
816  int dropped = 0;
817 
818  for (i = 0, j = 0; i < len; ++i) {
819  pkt = pkt_tbl[i];
820 
822  odp_packet_free(pkt); /* Drop */
823  dropped++;
824  } else if (odp_unlikely(i != j++)) {
825  pkt_tbl[j-1] = pkt;
826  }
827  }
828 
829  return dropped;
830 }
831 
838 static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len)
839 {
840  odp_packet_t pkt;
841  odph_ethhdr_t *eth;
842  odph_ethaddr_t tmp_addr;
843  odph_ipv4hdr_t *ip;
844  odp_u32be_t ip_tmp_addr; /* tmp ip addr */
845  unsigned i;
846 
847  for (i = 0; i < len; ++i) {
848  pkt = pkt_tbl[i];
849  if (odp_packet_has_eth(pkt)) {
850  eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL);
851 
852  tmp_addr = eth->dst;
853  eth->dst = eth->src;
854  eth->src = tmp_addr;
855 
856  if (odp_packet_has_ipv4(pkt)) {
857  /* IPv4 */
858  ip = (odph_ipv4hdr_t *)
859  odp_packet_l3_ptr(pkt, NULL);
860 
861  ip_tmp_addr = ip->src_addr;
862  ip->src_addr = ip->dst_addr;
863  ip->dst_addr = ip_tmp_addr;
864  }
865  }
866  }
867 }
868 
869 static int convert_str_to_pmr_enum(char *token, odp_cls_pmr_term_t *term)
870 {
871  if (NULL == token)
872  return -1;
873 
874  if (strcasecmp(token, "ODP_PMR_ETHTYPE_0") == 0) {
875  *term = ODP_PMR_ETHTYPE_0;
876  return 0;
877  } else if (strcasecmp(token, "ODP_PMR_ETHTYPE_X") == 0) {
878  *term = ODP_PMR_ETHTYPE_X;
879  return 0;
880  } else if (strcasecmp(token, "ODP_PMR_VLAN_ID_0") == 0) {
881  *term = ODP_PMR_VLAN_ID_0;
882  return 0;
883  } else if (strcasecmp(token, "ODP_PMR_VLAN_ID_X") == 0) {
884  *term = ODP_PMR_VLAN_ID_X;
885  return 0;
886  } else if (strcasecmp(token, "ODP_PMR_UDP_DPORT") == 0) {
887  *term = ODP_PMR_UDP_DPORT;
888  return 0;
889  } else if (strcasecmp(token, "ODP_PMR_TCP_DPORT") == 0) {
890  *term = ODP_PMR_TCP_DPORT;
891  return 0;
892  } else if (strcasecmp(token, "ODP_PMR_UDP_SPORT") == 0) {
893  *term = ODP_PMR_UDP_SPORT;
894  return 0;
895  } else if (strcasecmp(token, "ODP_PMR_TCP_SPORT") == 0) {
896  *term = ODP_PMR_TCP_SPORT;
897  return 0;
898  } else if (strcasecmp(token, "ODP_PMR_DIP_ADDR") == 0) {
899  *term = ODP_PMR_DIP_ADDR;
900  return 0;
901  } else if (strcasecmp(token, "ODP_PMR_SIP_ADDR") == 0) {
902  *term = ODP_PMR_SIP_ADDR;
903  return 0;
904  } else if (strcasecmp(token, "ODP_PMR_DMAC") == 0) {
905  *term = ODP_PMR_DMAC;
906  return 0;
907  } else if (strcasecmp(token, "ODP_PMR_CUSTOM_FRAME") == 0) {
908  *term = ODP_PMR_CUSTOM_FRAME;
909  return 0;
910  } else if (strcasecmp(token, "ODP_PMR_CUSTOM_L3") == 0) {
911  *term = ODP_PMR_CUSTOM_L3;
912  return 0;
913  }
914 
915  return -1;
916 }
917 
918 static int parse_pmr_policy(appl_args_t *appl_args, char *optarg)
919 {
920  int policy_count;
921  char *token, *cos0, *cos1, *cur_char;
922  size_t len;
923  odp_cls_pmr_term_t term;
924  global_statistics *stats;
925  odph_ethaddr_t mac;
926  char *pmr_str;
927  uint32_t offset, ip_addr, u32;
928  unsigned long int value, mask;
929  uint16_t u16;
930  int val_sz, mask_sz;
931 
932  policy_count = appl_args->policy_count;
933  stats = appl_args->stats;
934 
935  /* last array index is needed for default queue */
936  if (policy_count >= MAX_PMR_COUNT - 1) {
937  ODPH_ERR("Too many policies. Max count is %i.\n",
938  MAX_PMR_COUNT - 1);
939  return -1;
940  }
941 
942  len = strlen(optarg);
943  len++;
944  pmr_str = malloc(len);
945  if (pmr_str == NULL) {
946  ODPH_ERR("Memory allocation failed\n");
947  return -1;
948  }
949  strcpy(pmr_str, optarg);
950 
951  /* PMR TERM */
952  /* <term>:<xxx>:<yyy>:<src_cos>:<dst_cos> */
953  token = strtok(pmr_str, ":");
954  if (convert_str_to_pmr_enum(token, &term)) {
955  ODPH_ERR("Invalid ODP_PMR_TERM string\n");
956  goto error;
957  }
958  stats[policy_count].rule.term = term;
959  stats[policy_count].rule.offset = 0;
960 
961  /* PMR value */
962  switch (term) {
963  case ODP_PMR_ETHTYPE_0:
964  /* Fall through */
965  case ODP_PMR_ETHTYPE_X:
966  /* Fall through */
967  /* :<type>:<mask> */
968  case ODP_PMR_VLAN_ID_0:
969  /* Fall through */
970  case ODP_PMR_VLAN_ID_X:
971  /* Fall through */
972  /* :<vlan_id>:<mask> */
973  case ODP_PMR_UDP_DPORT:
974  /* Fall through */
975  case ODP_PMR_TCP_DPORT:
976  /* Fall through */
977  case ODP_PMR_UDP_SPORT:
978  /* Fall through */
979  case ODP_PMR_TCP_SPORT:
980  /* :<port>:<mask> */
981  token = strtok(NULL, ":");
982  odph_strcpy(stats[policy_count].value, token,
983  DISPLAY_STRING_LEN);
984  value = strtoul(token, NULL, 0);
985  u16 = value;
986  u16 = odp_cpu_to_be_16(u16);
987  memcpy(stats[policy_count].rule.value_be, &u16, sizeof(u16));
988 
989  token = strtok(NULL, ":");
990  odph_strcpy(stats[policy_count].mask, token,
991  DISPLAY_STRING_LEN);
992  mask = strtoul(token, NULL, 0);
993  u16 = mask;
994  u16 = odp_cpu_to_be_16(u16);
995  memcpy(stats[policy_count].rule.mask_be, &u16, sizeof(u16));
996 
997  stats[policy_count].rule.val_sz = 2;
998  break;
999  case ODP_PMR_DIP_ADDR:
1000  /* Fall through */
1001  case ODP_PMR_SIP_ADDR:
1002  /* :<IP addr>:<mask> */
1003  token = strtok(NULL, ":");
1004  odph_strcpy(stats[policy_count].value, token,
1005  DISPLAY_STRING_LEN);
1006 
1007  if (odph_ipv4_addr_parse(&ip_addr, token)) {
1008  ODPH_ERR("Bad IP address\n");
1009  goto error;
1010  }
1011 
1012  u32 = odp_cpu_to_be_32(ip_addr);
1013  memcpy(stats[policy_count].rule.value_be, &u32, sizeof(u32));
1014 
1015  token = strtok(NULL, ":");
1016  odph_strcpy(stats[policy_count].mask, token,
1017  DISPLAY_STRING_LEN);
1018  mask = strtoul(token, NULL, 0);
1019  u32 = mask;
1020  u32 = odp_cpu_to_be_32(u32);
1021  memcpy(stats[policy_count].rule.mask_be, &u32, sizeof(u32));
1022 
1023  stats[policy_count].rule.val_sz = 4;
1024  break;
1025  case ODP_PMR_DMAC:
1026  /* :<MAC addr>:<mask> */
1027  token = strtok(NULL, ":");
1028  odph_strcpy(stats[policy_count].value, token,
1029  DISPLAY_STRING_LEN);
1030 
1031  /* Replace hyphens in the MAC string with colons to be compatible with
1032  * odph_eth_addr_parse(). */
1033  cur_char = token;
1034  while ((cur_char = strchr(cur_char, '-')) != NULL)
1035  *cur_char++ = ':';
1036 
1037  if (odph_eth_addr_parse(&mac, token)) {
1038  ODPH_ERR("Invalid MAC address. Use format 11-22-33-44-55-66.\n");
1039  goto error;
1040  }
1041 
1042  memcpy(stats[policy_count].rule.value_be, mac.addr, ODPH_ETHADDR_LEN);
1043  stats[policy_count].rule.val_sz = 6;
1044 
1045  token = strtok(NULL, ":");
1046  odph_strcpy(stats[policy_count].mask, token, DISPLAY_STRING_LEN);
1047  mask_sz = parse_custom(token, stats[policy_count].rule.mask_be, ODPH_ETHADDR_LEN);
1048  if (mask_sz != ODPH_ETHADDR_LEN) {
1049  ODPH_ERR("Invalid mask. Provide mask without 0x prefix.\n");
1050  goto error;
1051  }
1052  break;
1053  case ODP_PMR_CUSTOM_FRAME:
1054  /* Fall through */
1055  case ODP_PMR_CUSTOM_L3:
1056  /* :<offset>:<value>:<mask> */
1057  token = strtok(NULL, ":");
1058  errno = 0;
1059  offset = strtoul(token, NULL, 0);
1060  stats[policy_count].rule.offset = offset;
1061  if (errno)
1062  goto error;
1063 
1064  token = strtok(NULL, ":");
1065  odph_strcpy(stats[policy_count].value, token,
1066  DISPLAY_STRING_LEN);
1067  val_sz = parse_custom(token,
1068  stats[policy_count].rule.value_be,
1069  MAX_VAL_SIZE);
1070  stats[policy_count].rule.val_sz = val_sz;
1071  if (val_sz <= 0)
1072  goto error;
1073 
1074  token = strtok(NULL, ":");
1075  odph_strcpy(stats[policy_count].mask, token,
1076  DISPLAY_STRING_LEN);
1077  mask_sz = parse_custom(token,
1078  stats[policy_count].rule.mask_be,
1079  MAX_VAL_SIZE);
1080  if (mask_sz != val_sz)
1081  goto error;
1082  break;
1083  default:
1084  goto error;
1085  }
1086 
1087  /* Optional source CoS name and name of this CoS
1088  * :<src_cos>:<cos> */
1089  cos0 = strtok(NULL, ":");
1090  cos1 = strtok(NULL, ":");
1091  if (cos0 == NULL)
1092  goto error;
1093 
1094  if (cos1) {
1095  stats[policy_count].has_src_cos = 1;
1096  odph_strcpy(stats[policy_count].src_cos_name, cos0,
1098  odph_strcpy(stats[policy_count].cos_name, cos1,
1100  } else {
1101  odph_strcpy(stats[policy_count].cos_name, cos0,
1103  }
1104 
1105  appl_args->policy_count++;
1106  free(pmr_str);
1107  return 0;
1108 
1109 error:
1110  free(pmr_str);
1111  return -1;
1112 }
1113 
1114 static int parse_policy_ci_pass_count(appl_args_t *appl_args, char *optarg)
1115 {
1116  int num_ci_pass_rules;
1117  char *token, *value;
1118  size_t len;
1119  ci_pass_counters *ci_pass_rules;
1120  char *count_str;
1121 
1122  num_ci_pass_rules = appl_args->num_ci_pass_rules;
1123  ci_pass_rules = appl_args->ci_pass_rules;
1124 
1125  /* last array index is needed for default queue */
1126  if (num_ci_pass_rules >= MAX_PMR_COUNT) {
1127  ODPH_ERR("Too many ci pass counters. Max count is %i.\n",
1128  MAX_PMR_COUNT);
1129  return -1;
1130  }
1131 
1132  len = strlen(optarg);
1133  len++;
1134  count_str = malloc(len);
1135  if (count_str == NULL) {
1136  ODPH_ERR("Memory allocation failed\n");
1137  return -1;
1138  }
1139  strcpy(count_str, optarg);
1140 
1141  token = strtok(count_str, ":");
1142  value = strtok(NULL, ":");
1143  if (!token || !value) {
1144  free(count_str);
1145  return -1;
1146  }
1147  strcpy(ci_pass_rules[num_ci_pass_rules].cos_name, token);
1148  ci_pass_rules[num_ci_pass_rules].count = atoll(value);
1149  appl_args->num_ci_pass_rules++;
1150  free(count_str);
1151  return 0;
1152 }
1153 
1161 static int parse_args(int argc, char *argv[], appl_args_t *appl_args)
1162 {
1163  int opt;
1164  size_t len;
1165  int i;
1166  int interface = 0;
1167  int ret = 0;
1168 
1169  static const struct option longopts[] = {
1170  {"count", required_argument, NULL, 'c'},
1171  {"interface", required_argument, NULL, 'i'},
1172  {"policy", required_argument, NULL, 'p'},
1173  {"mode", required_argument, NULL, 'm'},
1174  {"time", required_argument, NULL, 't'},
1175  {"ci_pass", required_argument, NULL, 'C'},
1176  {"promisc_mode", no_argument, NULL, 'P'},
1177  {"verbose", no_argument, NULL, 'v'},
1178  {"help", no_argument, NULL, 'h'},
1179  {"enable", required_argument, NULL, 'e'},
1180  {"layer", required_argument, NULL, 'l'},
1181  {"dedicated", required_argument, NULL, 'd'},
1182  {"size", required_argument, NULL, 's'},
1183  {"burst", required_argument, NULL, 'b'},
1184  {NULL, 0, NULL, 0}
1185  };
1186 
1187  static const char *shortopts = "+c:t:i:p:m:t:C:Pvhe:l:d:s:b:";
1188 
1189  appl_args->cpu_count = 1; /* Use one worker by default */
1190  appl_args->verbose = 0;
1191  appl_args->promisc_mode = 0;
1192  appl_args->classifier_enable = 1;
1193  appl_args->parse_layer = ODP_PROTO_LAYER_ALL;
1194  appl_args->cos_pools = 1;
1195  appl_args->pool_size = SHM_PKT_POOL_SIZE;
1196  appl_args->burst_size = DEF_PKT_BURST;
1197 
1198  while (ret == 0) {
1199  opt = getopt_long(argc, argv, shortopts,
1200  longopts, NULL);
1201 
1202  if (opt == -1)
1203  break; /* No more options */
1204 
1205  switch (opt) {
1206  case 'c':
1207  appl_args->cpu_count = atoi(optarg);
1208  break;
1209  case 'p':
1210  if (parse_pmr_policy(appl_args, optarg)) {
1211  ret = -1;
1212  break;
1213  }
1214  break;
1215  case 't':
1216  appl_args->time = atoi(optarg);
1217  break;
1218  case 'i':
1219  len = strlen(optarg);
1220  if (len == 0) {
1221  ret = -1;
1222  break;
1223  }
1224  len += 1; /* add room for '\0' */
1225 
1226  appl_args->if_name = malloc(len);
1227  if (appl_args->if_name == NULL) {
1228  ret = -1;
1229  break;
1230  }
1231 
1232  strcpy(appl_args->if_name, optarg);
1233  interface = 1;
1234  break;
1235  case 'm':
1236  i = atoi(optarg);
1237  if (i == 0)
1238  appl_args->appl_mode = APPL_MODE_DROP;
1239  else
1240  appl_args->appl_mode = APPL_MODE_REPLY;
1241  break;
1242  case 'C':
1243  if (parse_policy_ci_pass_count(appl_args, optarg)) {
1244  ret = -1;
1245  break;
1246  }
1247  break;
1248  case 'P':
1249  appl_args->promisc_mode = 1;
1250  break;
1251  case 'v':
1252  appl_args->verbose = 1;
1253  break;
1254  case 'h':
1255  ret = -1;
1256  break;
1257  case 'e':
1258  appl_args->classifier_enable = atoi(optarg);
1259  break;
1260  case 'l':
1261  appl_args->parse_layer = atoi(optarg);
1262  break;
1263  case 'd':
1264  appl_args->cos_pools = atoi(optarg);
1265  break;
1266  case 's':
1267  appl_args->pool_size = atoi(optarg);
1268  break;
1269  case 'b':
1270  appl_args->burst_size = atoi(optarg);
1271  break;
1272  default:
1273  break;
1274  }
1275  }
1276 
1277  if (!interface)
1278  ret = -1;
1279 
1280  if (appl_args->if_name == NULL)
1281  ret = -1;
1282 
1283  if (ret) {
1284  usage();
1285  free(appl_args->if_name);
1286  }
1287 
1288  /* reset optind from the getopt lib */
1289  optind = 1;
1290 
1291  return ret;
1292 }
1293 
1297 static void print_info(char *progname, appl_args_t *appl_args)
1298 {
1300 
1301  printf("Running ODP appl: \"%s\"\n"
1302  "-----------------\n"
1303  "Using IF: %s\n",
1304  progname, appl_args->if_name);
1305  printf("Promisc mode: %s\n", appl_args->promisc_mode ? "enabled" : "disabled");
1306  printf("\n\n");
1307  fflush(NULL);
1308 }
1309 
1313 static void usage(void)
1314 {
1315  printf("\n"
1316  "ODP Classifier example.\n"
1317  "Usage: odp_classifier OPTIONS\n"
1318  " E.g. odp_classifier -i eth1 -m 0 -p \"ODP_PMR_SIP_ADDR:10.10.10.0:0xFFFFFF00:queue1\" \\\n"
1319  " -p \"ODP_PMR_SIP_ADDR:10.10.10.10:0xFFFFFFFF:queue1:queue2\"\n"
1320  "\n"
1321  "The above example would classify:\n"
1322  " 1) Packets from source IP address 10.10.10.0/24 to queue1, except ...\n"
1323  " 2) Packets from source IP address 10.10.10.10 to queue2\n"
1324  " 3) All other packets to DefaultCos\n"
1325  "\n"
1326  "Mandatory OPTIONS:\n"
1327  " -i, --interface <interface name>\n"
1328  "\n"
1329  "Optional OPTIONS\n"
1330  " -p, --policy <PMR term>:<offset>:<value>:<mask>:<src queue>:<dst queue>\n"
1331  "\n"
1332  " <PMR term> PMR term name defined in odp_cls_pmr_term_t\n"
1333  " <offset> If term is ODP_PMR_CUSTOM_FRAME or _CUSTOM_L3, offset in bytes is used\n"
1334  " <value> PMR value to be matched\n"
1335  " <mask> PMR mask bits to be applied on the PMR value.\n"
1336  " CUSTOM PMR terms accept plain hex string, other PMR terms require\n"
1337  " hex string with '0x' prefix.\n"
1338  " <src queue> Optional name of the source queue (CoS). The default CoS is used when\n"
1339  " this is not defined.\n"
1340  " <dst queue> Name of the destination queue (CoS).\n"
1341  "\n"
1342  " -c, --count <num> CPU count, 0=all available, default=1\n"
1343  "\n"
1344  " -m, --mode <mode> 0: Packet Drop mode. Received packets will be dropped\n"
1345  " !0: Echo mode. Received packets will be sent back\n"
1346  " default: Packet Drop mode\n"
1347  "\n"
1348  " -t, --time <sec> !0: Time for which the classifier will be run in seconds\n"
1349  " 0: Runs in infinite loop\n"
1350  " default: Runs in infinite loop\n"
1351  "\n"
1352  " -e, --enable <enable> 0: Classifier is disabled\n"
1353  " 1: Classifier is enabled\n"
1354  " default: Classifier is enabled\n"
1355  "\n"
1356  " -l, --layer <layer> Parse packets up to and including this layer. See odp_proto_layer_t\n"
1357  " default: ODP_PROTO_LAYER_ALL\n"
1358  "\n"
1359  " -d, --dedicated <enable> 0: One pool for pktio and all CoSes\n"
1360  " 1: Dedicated pools for pktio and each CoS\n"
1361  " default: Dedicated pools\n"
1362  "\n"
1363  " -s, --size <num> Number of packets in each packet pool\n"
1364  " default: %d\n"
1365  "\n"
1366  " -b, --burst <num> Packet burst size\n"
1367  " default: %d\n"
1368  "\n"
1369  " -C, --ci_pass <dst queue:count>\n"
1370  " Minimum acceptable packet count for a CoS destination queue.\n"
1371  " If the received packet count is smaller than this value,\n"
1372  " the application will exit with an error.\n"
1373  " E.g: -C \"queue1:100\" -C \"queue2:200\" -C \"DefaultQueue:100\"\n"
1374  " -P, --promisc_mode Enable promiscuous mode.\n"
1375  " -v, --verbose Verbose output.\n"
1376  " -h, --help Display help and exit.\n"
1377  "\n", SHM_PKT_POOL_SIZE, DEF_PKT_BURST);
1378 }
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_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.
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.
#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.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#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_info(odp_queue_t queue, odp_queue_info_t *info)
Retrieve information about a queue.
@ ODP_QUEUE_TYPE_SCHED
Scheduled queue.
#define ODP_SCHED_SYNC_PARALLEL
Parallel scheduled queues.
int odp_schedule_multi(odp_queue_t *from, uint64_t wait, odp_event_t events[], int num)
Schedule multiple events.
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.
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.
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_pool_t pool
Pool associated with CoS.
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::@8::@10 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.
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.
Queue information Retrieve information about a queue with odp_queue_info()
const char * name
queue name
ODP Queue parameters.
odp_schedule_param_t sched
Scheduler parameters.
odp_queue_type_t type
Queue type.
odp_schedule_group_t group
Thread group.
odp_schedule_sync_t sync
Synchronization method.
struct odp_pktio_set_op_t::@104 op
Operation flags.
uint32_t promisc_mode
Promiscuous mode.