API Reference Manual  1.46.0
odp_pktio_ordered.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2016-2018 Linaro Limited
3  */
4 
14 #ifndef _GNU_SOURCE
15 #define _GNU_SOURCE
16 #endif
17 
18 #include <stdlib.h>
19 #include <getopt.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <inttypes.h>
23 
24 #include "dummy_crc.h"
25 
26 #include <odp_api.h>
27 #include <odp/helper/odph_api.h>
28 
47 #define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
48 
49 #define mix(a, b, c) \
50 { \
51  a -= c; a ^= rot(c, 4); c += b; \
52  b -= a; b ^= rot(a, 6); a += c; \
53  c -= b; c ^= rot(b, 8); b += a; \
54  a -= c; a ^= rot(c, 16); c += b; \
55  b -= a; b ^= rot(a, 19); a += c; \
56  c -= b; c ^= rot(b, 4); b += a; \
57 }
58 
59 #define final(a, b, c) \
60 { \
61  c ^= b; c -= rot(b, 14); \
62  a ^= c; a -= rot(c, 11); \
63  b ^= a; b -= rot(a, 25); \
64  c ^= b; c -= rot(b, 16); \
65  a ^= c; a -= rot(c, 4); \
66  b ^= a; b -= rot(a, 14); \
67  c ^= b; c -= rot(b, 24); \
68 }
69 
70 #define JHASH_GOLDEN_RATIO 0x9e3779b9
71 
72 /* Maximum pool and queue size */
73 #define MAX_NUM_PKT (8 * 1024)
74 
76 #define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
77 
79 #define PKT_POOL_BUF_SIZE 1856
80 
82 #define PKT_UAREA_SIZE 32
83 
85 #define MAX_PKT_BURST 32
86 
88 #define MAX_QUEUES 32
89 
91 #define MAX_PKTIOS 8
92 
94 #define MAX_FLOWS 128
95 
96 ODP_STATIC_ASSERT(MAX_PKTIOS < MAX_FLOWS,
97  "MAX_FLOWS must be greater than MAX_PKTIOS\n");
98 
100 #define MIN_PACKET_LEN (ODPH_ETHHDR_LEN + ODPH_IPV4HDR_LEN + ODPH_UDPHDR_LEN)
101 
103 #define DEF_NUM_RX_QUEUES 1
104 
106 #define DEF_NUM_FLOWS 12
107 
109 #define DEF_EXTRA_ROUNDS 15
110 
112 #define DEF_STATS_INT 1
113 
115 #define NO_PATH(file_name) (strrchr((file_name), '/') ? \
116  strrchr((file_name), '/') + 1 : (file_name))
117 
121 typedef enum pktin_mode_t {
122  SCHED_ORDERED = 0,
123  SCHED_ATOMIC,
124  SCHED_PARALLEL
125 } pktin_mode_t;
126 
130 typedef struct {
131  unsigned int cpu_count;
132  int if_count;
133  int addr_count;
134  int num_rx_q;
135  int num_flows;
136  int extra_rounds;
137  char **if_names;
138  odph_ethaddr_t addrs[MAX_PKTIOS];
139  pktin_mode_t in_mode;
140  int time;
141  int accuracy;
142  char *if_str;
143  int promisc_mode;
144 } appl_args_t;
145 
149 typedef struct {
150  odp_bool_t input_queue;
151  uint64_t idx;
152  uint64_t seq[MAX_FLOWS];
153 } qcontext_t;
154 
158 typedef struct {
159  uint64_t seq;
160  uint32_t crc;
161  uint16_t idx;
162  uint8_t src_idx;
163  uint8_t dst_idx;
165 } flow_t;
166 ODP_STATIC_ASSERT(sizeof(flow_t) <= PKT_UAREA_SIZE,
167  "Flow data doesn't fit in the packet user area\n");
168 
172 typedef union ODP_ALIGNED_CACHE {
173  struct {
175  uint64_t packets;
177  uint64_t rx_drops;
179  uint64_t tx_drops;
181  uint64_t invalid_seq;
182  } s;
183 
184  uint8_t padding[ODP_CACHE_LINE_SIZE];
185 } stats_t;
186 
190 typedef struct {
191  uint32_t src_ip;
192  uint32_t dst_ip;
193  uint16_t src_port;
194  uint16_t dst_port;
195  uint8_t proto;
196  uint8_t pad0;
197  uint16_t pad1;
198 } ipv4_tuple5_t;
199 
203 typedef struct {
204  odph_ethhdr_t *eth;
205  odph_ipv4hdr_t *ipv4;
206  odph_udphdr_t *udp;
207 } packet_hdr_t;
208 
212 typedef struct thread_args_t {
213  stats_t *stats;
214 } thread_args_t;
215 
219 typedef struct {
221  stats_t stats[MAX_WORKERS];
223  appl_args_t appl;
225  thread_args_t thread[MAX_WORKERS];
227  odph_ethaddr_t port_eth_addr[MAX_PKTIOS];
229  odph_ethaddr_t dst_eth_addr[MAX_PKTIOS];
231  int dst_port[MAX_PKTIOS];
233  odp_queue_t fqueue[MAX_PKTIOS][MAX_FLOWS];
235  qcontext_t flow_qcontext[MAX_PKTIOS][MAX_FLOWS];
237  qcontext_t input_qcontext[MAX_PKTIOS][MAX_QUEUES];
239  struct {
240  odp_pktio_t pktio;
241  odp_pktout_queue_t pktout[MAX_FLOWS];
242  odp_queue_t pktin[MAX_QUEUES];
243  int num_rx_queue;
244  int num_tx_queue;
245  } pktios[MAX_PKTIOS];
247  odp_barrier_t barrier;
249  odp_atomic_u32_t exit_threads;
250 } args_t;
251 
253 static args_t *gbl_args;
254 
260 static inline int lookup_dest_port(odp_packet_t pkt)
261 {
262  int i, src_idx;
263  odp_pktio_t pktio_src;
264 
265  pktio_src = odp_packet_input(pkt);
266 
267  for (src_idx = -1, i = 0; gbl_args->pktios[i].pktio
268  != ODP_PKTIO_INVALID; i++)
269  if (gbl_args->pktios[i].pktio == pktio_src)
270  src_idx = i;
271 
272  if (src_idx == -1)
273  ODPH_ABORT("Failed to determine pktio input\n");
274 
275  return gbl_args->dst_port[src_idx];
276 }
277 
287 static inline int packet_hdr(odp_packet_t pkt, packet_hdr_t *hdr)
288 {
289  uint8_t *udp;
290  uint16_t eth_type;
291  uint8_t ihl;
292 
293  if (odp_unlikely(odp_packet_seg_len(pkt) < MIN_PACKET_LEN))
294  return -1;
295 
296  if (odp_unlikely(!odp_packet_has_eth(pkt)))
297  return -1;
298 
299  hdr->eth = odp_packet_l2_ptr(pkt, NULL);
300  eth_type = odp_be_to_cpu_16(hdr->eth->type);
301  if (odp_unlikely(eth_type != ODPH_ETHTYPE_IPV4))
302  return -1;
303 
304  hdr->ipv4 = (odph_ipv4hdr_t *)(hdr->eth + 1);
305  if (odp_unlikely(hdr->ipv4->proto != ODPH_IPPROTO_UDP))
306  return -1;
307 
308  ihl = ODPH_IPV4HDR_IHL(hdr->ipv4->ver_ihl);
309  if (odp_unlikely(ihl < ODPH_IPV4HDR_IHL_MIN))
310  return -1;
311 
312  udp = (uint8_t *)hdr->ipv4 + (ihl * 4);
313 
314  hdr->udp = (odph_udphdr_t *)udp;
315 
316  return 0;
317 }
318 
326 static inline uint64_t calc_ipv4_5tuple_hash(ipv4_tuple5_t *tuple)
327 {
328  uint32_t a, b, c;
329 
330  a = tuple->proto + JHASH_GOLDEN_RATIO;
331  b = tuple->src_ip + JHASH_GOLDEN_RATIO;
332  c = tuple->dst_ip + JHASH_GOLDEN_RATIO;
333 
334  mix(a, b, c);
335 
336  a += ((uint32_t)tuple->src_port << 16) + tuple->dst_port + JHASH_GOLDEN_RATIO;
337  final(a, b, c);
338 
339  return c;
340 }
341 
349 static inline uint64_t calc_flow_idx(packet_hdr_t *hdr)
350 {
351  ipv4_tuple5_t tuple;
352  uint64_t idx;
353 
354  tuple.dst_ip = odp_be_to_cpu_32(hdr->ipv4->dst_addr);
355  tuple.src_ip = odp_be_to_cpu_32(hdr->ipv4->src_addr);
356  tuple.proto = hdr->ipv4->proto;
357  tuple.src_port = odp_be_to_cpu_16(hdr->udp->src_port);
358  tuple.dst_port = odp_be_to_cpu_16(hdr->udp->dst_port);
359  tuple.pad0 = 0;
360  tuple.pad1 = 0;
361  idx = calc_ipv4_5tuple_hash(&tuple);
362 
363  return idx % gbl_args->appl.num_flows;
364 }
365 
372 static inline void fill_eth_addrs(packet_hdr_t *hdr, int dst_port)
373 {
374  hdr->eth->src = gbl_args->port_eth_addr[dst_port];
375  hdr->eth->dst = gbl_args->dst_eth_addr[dst_port];
376 }
377 
387 static inline void process_flow(odp_event_t ev_tbl[], int num, stats_t *stats,
388  qcontext_t *qcontext,
389  odp_pktout_queue_t pktout[][MAX_FLOWS])
390 {
391  odp_packet_t pkt;
392  flow_t *flow;
393  uint64_t queue_seq;
394  int dst_if;
395  int i;
396  int sent;
397 
398  for (i = 0; i < num; i++) {
399  pkt = odp_packet_from_event(ev_tbl[i]);
400 
401  flow = odp_packet_user_area(pkt);
402 
403  queue_seq = qcontext->seq[flow->src_idx];
404 
405  /* Check sequence number */
406  if (gbl_args->appl.in_mode != SCHED_PARALLEL &&
407  odp_unlikely(flow->seq != queue_seq)) {
408  printf("Invalid sequence number: packet_seq=%" PRIu64 ""
409  " queue_seq=%" PRIu64 ", src_if=%" PRIu8 ", "
410  "dst_if=%" PRIu8 ", flow=%" PRIu16 "\n",
411  flow->seq, queue_seq, flow->src_idx,
412  flow->dst_idx, flow->idx);
413  qcontext->seq[flow->src_idx] = flow->seq + 1;
414  stats->s.invalid_seq++;
415  } else {
416  qcontext->seq[flow->src_idx]++;
417  }
418 
419  dst_if = flow->dst_idx;
420  sent = odp_pktout_send(pktout[dst_if][flow->idx], &pkt, 1);
421 
422  if (odp_unlikely(sent != 1)) {
423  stats->s.tx_drops++;
424  odp_packet_free(pkt);
425  }
426  stats->s.packets++;
427  }
428 }
429 
438 static inline void process_input(odp_event_t ev_tbl[], int num, stats_t *stats,
439  qcontext_t *qcontext)
440 {
441  flow_t *flow;
442  flow_t *flow_tbl[MAX_PKT_BURST];
443  int ret;
444  int i, j;
445  int pkts = 0;
446 
447  for (i = 0; i < num; i++) {
448  odp_packet_t pkt;
449  packet_hdr_t hdr;
450  int flow_idx;
451 
452  pkt = odp_packet_from_event(ev_tbl[i]);
453 
454  odp_packet_prefetch(pkt, 0, MIN_PACKET_LEN);
455 
456  ret = packet_hdr(pkt, &hdr);
457  if (odp_unlikely(ret)) {
458  odp_packet_free(pkt);
459  stats->s.rx_drops++;
460  continue;
461  }
462 
463  flow_idx = calc_flow_idx(&hdr);
464 
465  fill_eth_addrs(&hdr, flow_idx);
466 
467  flow = odp_packet_user_area(pkt);
468  flow->idx = flow_idx;
469  flow->src_idx = qcontext->idx;
470  flow->dst_idx = lookup_dest_port(pkt);
471  flow_tbl[pkts] = flow;
472 
473  /* Simulate "fat pipe" processing by generating extra work */
474  for (j = 0; j < gbl_args->appl.extra_rounds; j++)
475  flow->crc = dummy_hash_crc32c(odp_packet_data(pkt),
476  odp_packet_len(pkt), 0);
477  pkts++;
478  }
479 
480  if (odp_unlikely(!pkts))
481  return;
482 
483  /* Set sequence numbers */
484  if (gbl_args->appl.in_mode == SCHED_ORDERED)
486 
487  for (i = 0; i < pkts; i++) {
488  flow = flow_tbl[i];
489  flow->seq = qcontext->seq[flow->idx]++;
490  }
491 
492  if (gbl_args->appl.in_mode == SCHED_ORDERED)
494 
495  for (i = 0; i < pkts; i++) {
496  flow = flow_tbl[i];
497  ret = odp_queue_enq(gbl_args->fqueue[flow->dst_idx][flow->idx],
498  ev_tbl[i]);
499 
500  if (odp_unlikely(ret != 0)) {
501  ODPH_ERR("odp_queue_enq() failed\n");
502  stats->s.tx_drops++;
503  odp_event_free(ev_tbl[i]);
504  } else {
505  stats->s.packets++;
506  }
507  }
508 }
509 
515 static int run_worker(void *arg)
516 {
517  odp_event_t ev_tbl[MAX_PKT_BURST];
518  odp_queue_t queue;
519  odp_pktout_queue_t pktout[MAX_PKTIOS][MAX_FLOWS];
520  qcontext_t *qcontext;
521  thread_args_t *thr_args = arg;
522  stats_t *stats = thr_args->stats;
523  int pkts;
524  int i, j;
525 
526  memset(pktout, 0, sizeof(pktout));
527 
528  for (i = 0; i < gbl_args->appl.if_count; i++) {
529  for (j = 0; j < gbl_args->appl.num_flows; j++) {
530  pktout[i][j] = gbl_args->pktios[i].pktout[j %
531  gbl_args->pktios[i].num_tx_queue];
532  }
533  }
534  odp_barrier_wait(&gbl_args->barrier);
535 
536  /* Loop packets */
537  while (!odp_atomic_load_u32(&gbl_args->exit_threads)) {
538  pkts = odp_schedule_multi(&queue, ODP_SCHED_NO_WAIT, ev_tbl,
539  MAX_PKT_BURST);
540  if (pkts <= 0)
541  continue;
542 
543  qcontext = odp_queue_context(queue);
544 
545  if (qcontext->input_queue)
546  process_input(ev_tbl, pkts, stats, qcontext);
547  else
548  process_flow(ev_tbl, pkts, stats, qcontext, pktout);
549  }
550 
551  /* Free remaining events in queues */
552  while (1) {
553  odp_event_t ev;
554 
555  ev = odp_schedule(NULL,
557 
558  if (ev == ODP_EVENT_INVALID)
559  break;
560 
561  odp_event_free(ev);
562  }
563 
564  return 0;
565 }
566 
579 static int create_pktio(const char *dev, int idx, int num_rx, int num_tx,
580  odp_pool_t pool)
581 {
582  odp_pktio_t pktio;
583  odp_pktio_param_t pktio_param;
585  odp_pktio_config_t config;
586  odp_pktin_queue_param_t pktin_param;
587  odp_pktout_queue_param_t pktout_param;
588  odp_pktio_op_mode_t mode_rx;
589  odp_pktio_op_mode_t mode_tx;
590  int i;
591 
592  odp_pktio_param_init(&pktio_param);
593 
594  pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
595 
596  pktio = odp_pktio_open(dev, pool, &pktio_param);
597  if (pktio == ODP_PKTIO_INVALID) {
598  ODPH_ERR("Error: failed to open %s\n", dev);
599  return -1;
600  }
601 
602  printf("Created pktio %" PRIu64 " (%s)\n",
603  odp_pktio_to_u64(pktio), dev);
604 
605  if (odp_pktio_capability(pktio, &capa)) {
606  ODPH_ERR("Error: capability query failed %s\n", dev);
607  odp_pktio_close(pktio);
608  return -1;
609  }
610 
611  odp_pktio_config_init(&config);
613  odp_pktio_config(pktio, &config);
614 
615  if (gbl_args->appl.promisc_mode && odp_pktio_promisc_mode(pktio) != 1) {
616  if (!capa.set_op.op.promisc_mode) {
617  ODPH_ERR("Error: promisc mode set not supported %s\n",
618  dev);
619  return -1;
620  }
621 
622  /* Enable promisc mode */
623  if (odp_pktio_promisc_mode_set(pktio, true)) {
624  ODPH_ERR("Error: promisc mode enable failed %s\n", dev);
625  return -1;
626  }
627  }
628 
629  odp_pktin_queue_param_init(&pktin_param);
630  odp_pktout_queue_param_init(&pktout_param);
631 
632  mode_tx = ODP_PKTIO_OP_MT;
633  mode_rx = ODP_PKTIO_OP_MT;
634 
635  if (gbl_args->appl.in_mode == SCHED_ATOMIC) {
637  } else if (gbl_args->appl.in_mode == SCHED_PARALLEL) {
639  } else {
641  pktin_param.queue_param.sched.lock_count = 1;
642  }
645 
646  if (num_rx > (int)capa.max_input_queues) {
647  printf("Allocating %i shared input queues, %i requested\n",
648  capa.max_input_queues, num_rx);
649  num_rx = capa.max_input_queues;
650  mode_rx = ODP_PKTIO_OP_MT;
651  }
652 
653  if (num_tx > (int)capa.max_output_queues) {
654  printf("Allocating %i shared output queues, %i requested\n",
655  capa.max_output_queues, num_tx);
656  num_tx = capa.max_output_queues;
657  mode_tx = ODP_PKTIO_OP_MT;
658  }
659 
660  pktin_param.hash_enable = (num_rx > 1) ? 1 : 0;
661  pktin_param.hash_proto.proto.ipv4_udp = 1;
662  pktin_param.num_queues = num_rx;
663  pktin_param.op_mode = mode_rx;
664 
665  pktout_param.op_mode = mode_tx;
666  pktout_param.num_queues = num_tx;
667 
668  if (odp_pktin_queue_config(pktio, &pktin_param)) {
669  ODPH_ERR("Error: input queue config failed %s\n", dev);
670  return -1;
671  }
672 
673  if (odp_pktout_queue_config(pktio, &pktout_param)) {
674  ODPH_ERR("Error: output queue config failed %s\n", dev);
675  return -1;
676  }
677 
678  if (odp_pktin_event_queue(pktio, gbl_args->pktios[idx].pktin,
679  num_rx) != num_rx) {
680  ODPH_ERR("Error: pktin event queue query failed %s\n", dev);
681  return -1;
682  }
683 
684  /* Set queue contexts */
685  for (i = 0; i < num_rx; i++) {
686  gbl_args->input_qcontext[idx][i].idx = idx;
687  gbl_args->input_qcontext[idx][i].input_queue = 1;
688 
689  if (odp_queue_context_set(gbl_args->pktios[idx].pktin[i],
690  &gbl_args->input_qcontext[idx][i],
691  sizeof(qcontext_t))) {
692  ODPH_ERR("Error: pktin queue context set failed %s\n",
693  dev);
694  return -1;
695  }
696  }
697 
698  if (odp_pktout_queue(pktio,
699  gbl_args->pktios[idx].pktout,
700  num_tx) != num_tx) {
701  ODPH_ERR("Error: pktout queue query failed %s\n", dev);
702  return -1;
703  }
704 
705  printf("Created %i input and %i output queues on (%s)\n",
706  num_rx, num_tx, dev);
707 
708  gbl_args->pktios[idx].num_rx_queue = num_rx;
709  gbl_args->pktios[idx].num_tx_queue = num_tx;
710  gbl_args->pktios[idx].pktio = pktio;
711 
712  return 0;
713 }
714 
724 static int print_speed_stats(int num_workers, stats_t *thr_stats,
725  int duration, int timeout)
726 {
727  uint64_t pkts = 0;
728  uint64_t pkts_prev = 0;
729  uint64_t pps;
730  uint64_t rx_drops, tx_drops, invalid_seq;
731  uint64_t maximum_pps = 0;
732  int i;
733  int elapsed = 0;
734  int stats_enabled = 1;
735  int loop_forever = (duration == 0);
736 
737  if (timeout <= 0) {
738  stats_enabled = 0;
739  timeout = 1;
740  }
741  /* Wait for all threads to be ready*/
742  odp_barrier_wait(&gbl_args->barrier);
743 
744  do {
745  pkts = 0;
746  rx_drops = 0;
747  tx_drops = 0;
748  invalid_seq = 0;
749 
750  sleep(timeout);
751 
752  for (i = 0; i < num_workers; i++) {
753  pkts += thr_stats[i].s.packets;
754  rx_drops += thr_stats[i].s.rx_drops;
755  tx_drops += thr_stats[i].s.tx_drops;
756  invalid_seq += thr_stats[i].s.invalid_seq;
757  }
758  if (stats_enabled) {
759  pps = (pkts - pkts_prev) / timeout;
760  if (pps > maximum_pps)
761  maximum_pps = pps;
762  printf("%" PRIu64 " pps, %" PRIu64 " max pps, ", pps,
763  maximum_pps);
764 
765  printf("%" PRIu64 " rx drops, %" PRIu64 " tx drops, ",
766  rx_drops, tx_drops);
767 
768  printf("%" PRIu64 " invalid seq\n", invalid_seq);
769 
770  pkts_prev = pkts;
771  }
772  elapsed += timeout;
773  } while (loop_forever || (elapsed < duration));
774 
775  if (stats_enabled)
776  printf("TEST RESULT: %" PRIu64 " maximum packets per second.\n",
777  maximum_pps);
778 
779  return (pkts > 100 && !invalid_seq) ? 0 : -1;
780 }
781 
787 static int find_dest_port(int port)
788 {
789  /* Even number of ports */
790  if (gbl_args->appl.if_count % 2 == 0)
791  return (port % 2 == 0) ? port + 1 : port - 1;
792 
793  /* Odd number of ports */
794  if (port == gbl_args->appl.if_count - 1)
795  return 0;
796  else
797  return port + 1;
798 }
799 
803 static void init_forwarding_tbl(void)
804 {
805  int rx_idx;
806 
807  for (rx_idx = 0; rx_idx < gbl_args->appl.if_count; rx_idx++)
808  gbl_args->dst_port[rx_idx] = find_dest_port(rx_idx);
809 }
810 
814 static void usage(char *progname)
815 {
816  printf("\n"
817  "OpenDataPlane ordered pktio application.\n"
818  "\n"
819  "Usage: %s OPTIONS\n"
820  " E.g. %s -i eth0,eth1\n"
821  " In the above example,\n"
822  " eth0 will send pkts to eth1 and vice versa\n"
823  "\n"
824  "Mandatory OPTIONS:\n"
825  " -i, --interface Eth interfaces (comma-separated, no spaces)\n"
826  " Interface count min 1, max %i\n"
827  "\n"
828  "Optional OPTIONS:\n"
829  " -m, --mode Packet input mode\n"
830  " 0: Scheduled ordered queues (default)\n"
831  " 1: Scheduled atomic queues\n"
832  " 2: Scheduled parallel queues (packet order not maintained)\n"
833  " -r, --num_rx_q Number of RX queues per interface\n"
834  " -f, --num_flows Number of packet flows\n"
835  " -e, --extra_input <number> Number of extra input processing rounds\n"
836  " -c, --count <number> CPU count, 0=all available, default=1\n"
837  " -t, --time <number> Time in seconds to run.\n"
838  " -a, --accuracy <number> Statistics print interval in seconds\n"
839  " (default is 1 second).\n"
840  " -d, --dst_addr Destination addresses (comma-separated, no spaces)\n"
841  " -P, --promisc_mode Enable promiscuous mode.\n"
842  " -h, --help Display help and exit.\n\n"
843  "\n", NO_PATH(progname), NO_PATH(progname), MAX_PKTIOS
844  );
845 }
846 
854 static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
855 {
856  int opt;
857  char *token;
858  char *addr_str;
859  size_t len;
860  int i;
861  static const struct option longopts[] = {
862  {"count", required_argument, NULL, 'c'},
863  {"time", required_argument, NULL, 't'},
864  {"accuracy", required_argument, NULL, 'a'},
865  {"interface", required_argument, NULL, 'i'},
866  {"mode", required_argument, NULL, 'm'},
867  {"dst_addr", required_argument, NULL, 'd'},
868  {"num_rx_q", required_argument, NULL, 'r'},
869  {"num_flows", required_argument, NULL, 'f'},
870  {"extra_input", required_argument, NULL, 'e'},
871  {"promisc_mode", no_argument, NULL, 'P'},
872  {"help", no_argument, NULL, 'h'},
873  {NULL, 0, NULL, 0}
874  };
875 
876  static const char *shortopts = "+c:t:a:i:m:d:r:f:e:Ph";
877 
878  appl_args->time = 0; /* loop forever if time to run is 0 */
879  appl_args->accuracy = DEF_STATS_INT;
880  appl_args->cpu_count = 1; /* use one worker by default */
881  appl_args->num_rx_q = DEF_NUM_RX_QUEUES;
882  appl_args->num_flows = DEF_NUM_FLOWS;
883  appl_args->extra_rounds = DEF_EXTRA_ROUNDS;
884  appl_args->promisc_mode = 0;
885 
886  while (1) {
887  opt = getopt_long(argc, argv, shortopts, longopts, NULL);
888 
889  if (opt == -1)
890  break; /* No more options */
891 
892  switch (opt) {
893  case 'c':
894  appl_args->cpu_count = atoi(optarg);
895  break;
896  case 't':
897  appl_args->time = atoi(optarg);
898  break;
899  case 'a':
900  appl_args->accuracy = atoi(optarg);
901  break;
902  /* parse packet-io interface names */
903  case 'd':
904  len = strlen(optarg);
905  if (len == 0) {
906  usage(argv[0]);
907  exit(EXIT_FAILURE);
908  }
909  len += 1; /* add room for '\0' */
910 
911  addr_str = malloc(len);
912  if (addr_str == NULL) {
913  usage(argv[0]);
914  exit(EXIT_FAILURE);
915  }
916 
917  /* store the mac addresses names */
918  strcpy(addr_str, optarg);
919  for (token = strtok(addr_str, ","), i = 0;
920  token != NULL; token = strtok(NULL, ","), i++) {
921  if (i >= MAX_PKTIOS) {
922  printf("too many MAC addresses\n");
923  usage(argv[0]);
924  exit(EXIT_FAILURE);
925  }
926  if (odph_eth_addr_parse(&appl_args->addrs[i],
927  token) != 0) {
928  printf("invalid MAC address\n");
929  usage(argv[0]);
930  exit(EXIT_FAILURE);
931  }
932  }
933  appl_args->addr_count = i;
934  if (appl_args->addr_count < 1) {
935  usage(argv[0]);
936  exit(EXIT_FAILURE);
937  }
938  free(addr_str);
939  break;
940  case 'i':
941  len = strlen(optarg);
942  if (len == 0) {
943  usage(argv[0]);
944  exit(EXIT_FAILURE);
945  }
946  len += 1; /* add room for '\0' */
947 
948  appl_args->if_str = malloc(len);
949  if (appl_args->if_str == NULL) {
950  usage(argv[0]);
951  exit(EXIT_FAILURE);
952  }
953 
954  /* count the number of tokens separated by ',' */
955  strcpy(appl_args->if_str, optarg);
956  for (token = strtok(appl_args->if_str, ","), i = 0;
957  token != NULL;
958  token = strtok(NULL, ","), i++)
959  ;
960 
961  appl_args->if_count = i;
962 
963  if (appl_args->if_count < 1 ||
964  appl_args->if_count > MAX_PKTIOS) {
965  usage(argv[0]);
966  exit(EXIT_FAILURE);
967  }
968 
969  /* allocate storage for the if names */
970  appl_args->if_names =
971  calloc(appl_args->if_count, sizeof(char *));
972 
973  /* store the if names (reset names string) */
974  strcpy(appl_args->if_str, optarg);
975  for (token = strtok(appl_args->if_str, ","), i = 0;
976  token != NULL; token = strtok(NULL, ","), i++) {
977  appl_args->if_names[i] = token;
978  }
979  break;
980  case 'm':
981  i = atoi(optarg);
982  if (i == 1)
983  appl_args->in_mode = SCHED_ATOMIC;
984  else if (i == 2)
985  appl_args->in_mode = SCHED_PARALLEL;
986  else
987  appl_args->in_mode = SCHED_ORDERED;
988  break;
989  case 'r':
990  appl_args->num_rx_q = atoi(optarg);
991  break;
992  case 'f':
993  appl_args->num_flows = atoi(optarg);
994  break;
995  case 'e':
996  appl_args->extra_rounds = atoi(optarg);
997  break;
998  case 'P':
999  appl_args->promisc_mode = 1;
1000  break;
1001  case 'h':
1002  usage(argv[0]);
1003  exit(EXIT_SUCCESS);
1004  break;
1005  default:
1006  break;
1007  }
1008  }
1009 
1010  if (appl_args->num_flows > MAX_FLOWS) {
1011  printf("Too many flows requested %d, max: %d\n",
1012  appl_args->num_flows, MAX_FLOWS);
1013  exit(EXIT_FAILURE);
1014  }
1015 
1016  if (appl_args->if_count == 0 || appl_args->num_flows == 0 ||
1017  appl_args->num_rx_q == 0) {
1018  usage(argv[0]);
1019  exit(EXIT_FAILURE);
1020  }
1021  if (appl_args->addr_count != 0 &&
1022  appl_args->addr_count != appl_args->if_count) {
1023  printf("Number of destination addresses differs from number"
1024  " of interfaces\n");
1025  usage(argv[0]);
1026  exit(EXIT_FAILURE);
1027  }
1028 
1029  optind = 1; /* reset 'extern optind' from the getopt lib */
1030 }
1031 
1035 static void print_info(char *progname, appl_args_t *appl_args)
1036 {
1037  int i;
1038 
1040 
1041  printf("%s options\n"
1042  "-------------------------\n"
1043  "IF-count: %i\n"
1044  "Using IFs: ",
1045  progname, appl_args->if_count);
1046  for (i = 0; i < appl_args->if_count; ++i)
1047  printf(" %s", appl_args->if_names[i]);
1048  printf("\n"
1049  "Input queues: %d\n"
1050  "Mode: %s\n"
1051  "Flows: %d\n"
1052  "Extra rounds: %d\n"
1053  "Promisc mode: %s\n", appl_args->num_rx_q,
1054  (appl_args->in_mode == SCHED_ATOMIC) ? "PKTIN_SCHED_ATOMIC" :
1055  (appl_args->in_mode == SCHED_PARALLEL ? "PKTIN_SCHED_PARALLEL" :
1056  "PKTIN_SCHED_ORDERED"), appl_args->num_flows,
1057  appl_args->extra_rounds, appl_args->promisc_mode ?
1058  "enabled" : "disabled");
1059  fflush(NULL);
1060 }
1061 
1062 static void gbl_args_init(args_t *args)
1063 {
1064  int pktio, queue;
1065 
1066  memset(args, 0, sizeof(args_t));
1067  odp_atomic_init_u32(&args->exit_threads, 0);
1068 
1069  for (pktio = 0; pktio < MAX_PKTIOS; pktio++) {
1070  args->pktios[pktio].pktio = ODP_PKTIO_INVALID;
1071 
1072  for (queue = 0; queue < MAX_QUEUES; queue++)
1073  args->pktios[pktio].pktin[queue] = ODP_QUEUE_INVALID;
1074  }
1075 }
1076 
1080 int main(int argc, char *argv[])
1081 {
1082  odp_cpumask_t cpumask;
1083  odp_instance_t instance;
1084  odp_init_t init_param;
1085  odp_pool_t pool;
1086  odp_pool_param_t params;
1087  odp_shm_t shm;
1088  odp_schedule_capability_t schedule_capa;
1089  odp_schedule_config_t schedule_config;
1090  odp_pool_capability_t pool_capa;
1091  odph_ethaddr_t new_addr;
1092  odph_helper_options_t helper_options;
1093  odph_thread_t thread_tbl[MAX_WORKERS];
1094  odph_thread_common_param_t thr_common;
1095  odph_thread_param_t thr_param[MAX_WORKERS];
1096  stats_t *stats;
1097  char cpumaskstr[ODP_CPUMASK_STR_SIZE];
1098  int i, j;
1099  int if_count;
1100  int ret;
1101  int num_workers;
1102  uint32_t queue_size, pool_size;
1103 
1104  /* Let helper collect its own arguments (e.g. --odph_proc) */
1105  argc = odph_parse_options(argc, argv);
1106  if (odph_options(&helper_options)) {
1107  ODPH_ERR("Error: reading ODP helper options failed.\n");
1108  exit(EXIT_FAILURE);
1109  }
1110 
1111  odp_init_param_init(&init_param);
1112  init_param.mem_model = helper_options.mem_model;
1113 
1114  /* Init ODP before calling anything else */
1115  if (odp_init_global(&instance, &init_param, NULL)) {
1116  ODPH_ERR("Error: ODP global init failed.\n");
1117  exit(EXIT_FAILURE);
1118  }
1119 
1120  /* Init this thread */
1121  if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
1122  ODPH_ERR("Error: ODP local init failed.\n");
1123  exit(EXIT_FAILURE);
1124  }
1125 
1126  if (odp_schedule_capability(&schedule_capa)) {
1127  printf("Error: Schedule capa failed.\n");
1128  return -1;
1129  }
1130 
1131  if (odp_pool_capability(&pool_capa)) {
1132  ODPH_ERR("Error: Pool capa failed\n");
1133  exit(EXIT_FAILURE);
1134  }
1135 
1136  /* Reserve memory for args from shared mem */
1137  shm = odp_shm_reserve("shm_args", sizeof(args_t),
1138  ODP_CACHE_LINE_SIZE, 0);
1139 
1140  if (shm == ODP_SHM_INVALID) {
1141  ODPH_ERR("Error: shared mem reserve failed.\n");
1142  exit(EXIT_FAILURE);
1143  }
1144 
1145  gbl_args = odp_shm_addr(shm);
1146 
1147  if (gbl_args == NULL) {
1148  ODPH_ERR("Error: shared mem alloc failed.\n");
1149  odp_shm_free(shm);
1150  exit(EXIT_FAILURE);
1151  }
1152  gbl_args_init(gbl_args);
1153 
1154  /* Parse and store the application arguments */
1155  parse_args(argc, argv, &gbl_args->appl);
1156 
1157  odp_schedule_config_init(&schedule_config);
1158  odp_schedule_config(&schedule_config);
1159 
1160  if (gbl_args->appl.in_mode == SCHED_ORDERED) {
1161  /* At least one ordered lock required */
1162  if (schedule_capa.max_ordered_locks < 1) {
1163  ODPH_ERR("Error: Ordered locks not available.\n");
1164  exit(EXIT_FAILURE);
1165  }
1166  }
1167  /* Print both system and application information */
1168  print_info(NO_PATH(argv[0]), &gbl_args->appl);
1169 
1170  num_workers = MAX_WORKERS;
1171  if (gbl_args->appl.cpu_count && gbl_args->appl.cpu_count < MAX_WORKERS)
1172  num_workers = gbl_args->appl.cpu_count;
1173 
1174  /* Get default worker cpumask */
1175  num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
1176  (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
1177 
1178  if_count = gbl_args->appl.if_count;
1179 
1180  printf("Num worker threads: %i\n", num_workers);
1181  printf("First CPU: %i\n", odp_cpumask_first(&cpumask));
1182  printf("CPU mask: %s\n\n", cpumaskstr);
1183 
1184  pool_size = MAX_NUM_PKT;
1185  if (pool_capa.pkt.max_num && pool_capa.pkt.max_num < MAX_NUM_PKT)
1186  pool_size = pool_capa.pkt.max_num;
1187 
1188  queue_size = MAX_NUM_PKT;
1189  if (schedule_config.queue_size &&
1190  schedule_config.queue_size < MAX_NUM_PKT)
1191  queue_size = schedule_config.queue_size;
1192 
1193  /* Pool should not be larger than queue, otherwise queue enqueues at
1194  * packet input may fail. */
1195  if (pool_size > queue_size)
1196  pool_size = queue_size;
1197 
1198  /* Create packet pool */
1199  odp_pool_param_init(&params);
1200  params.pkt.seg_len = PKT_POOL_BUF_SIZE;
1201  params.pkt.len = PKT_POOL_BUF_SIZE;
1202  params.pkt.num = pool_size;
1203  params.pkt.uarea_size = PKT_UAREA_SIZE;
1204  params.type = ODP_POOL_PACKET;
1205 
1206  pool = odp_pool_create("packet pool", &params);
1207 
1208  if (pool == ODP_POOL_INVALID) {
1209  ODPH_ERR("Error: packet pool create failed.\n");
1210  exit(EXIT_FAILURE);
1211  }
1212  odp_pool_print(pool);
1213 
1214  init_forwarding_tbl();
1215 
1216  for (i = 0; i < if_count; ++i) {
1217  const char *dev = gbl_args->appl.if_names[i];
1218  int num_rx, num_tx;
1219 
1220  num_rx = gbl_args->appl.num_rx_q;
1221  num_tx = gbl_args->appl.num_flows;
1222 
1223  if (create_pktio(dev, i, num_rx, num_tx, pool))
1224  exit(EXIT_FAILURE);
1225 
1226  /* Save interface ethernet address */
1227  if (odp_pktio_mac_addr(gbl_args->pktios[i].pktio,
1228  gbl_args->port_eth_addr[i].addr,
1229  ODPH_ETHADDR_LEN) != ODPH_ETHADDR_LEN) {
1230  ODPH_ERR("Error: interface ethernet address unknown\n");
1231  exit(EXIT_FAILURE);
1232  }
1233 
1234  odp_pktio_print(gbl_args->pktios[i].pktio);
1235 
1236  /* Save destination eth address */
1237  /* 02:00:00:00:00:XX */
1238  memset(&new_addr, 0, sizeof(odph_ethaddr_t));
1239  if (gbl_args->appl.addr_count) {
1240  memcpy(&new_addr, &gbl_args->appl.addrs[i],
1241  sizeof(odph_ethaddr_t));
1242  } else {
1243  new_addr.addr[0] = 0x02;
1244  new_addr.addr[5] = i;
1245  }
1246  gbl_args->dst_eth_addr[i] = new_addr;
1247  }
1248 
1249  gbl_args->pktios[i].pktio = ODP_PKTIO_INVALID;
1250 
1251  /* Allocate the same number of flows to each interface */
1252  for (i = 0; i < if_count; i++) {
1254 
1255  if (odp_pktio_capability(gbl_args->pktios[i].pktio, &capa)) {
1256  ODPH_ERR("Error: pktio capability failed.\n");
1257  exit(EXIT_FAILURE);
1258  }
1259 
1260  if ((uint32_t)gbl_args->appl.num_flows > capa.max_output_queues)
1261  gbl_args->appl.num_flows = capa.max_output_queues;
1262  }
1263 
1264  /* Create atomic queues for packet tagging */
1265  for (i = 0; i < if_count; i++) {
1266  for (j = 0; j < gbl_args->appl.num_flows; j++) {
1267  odp_queue_t queue;
1268  odp_queue_param_t qparam;
1269  char qname[ODP_QUEUE_NAME_LEN];
1270 
1271  snprintf(qname, sizeof(qname), "flow_%d_%d", i, j);
1272 
1273  odp_queue_param_init(&qparam);
1274  qparam.type = ODP_QUEUE_TYPE_SCHED;
1276  qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC;
1277  qparam.sched.group = ODP_SCHED_GROUP_ALL;
1278  qparam.size = queue_size;
1279 
1280  gbl_args->flow_qcontext[i][j].idx = i;
1281  gbl_args->flow_qcontext[i][j].input_queue = 0;
1282  qparam.context = &gbl_args->flow_qcontext[i][j];
1283  qparam.context_len = sizeof(qcontext_t);
1284 
1285  queue = odp_queue_create(qname, &qparam);
1286  if (queue == ODP_QUEUE_INVALID) {
1287  ODPH_ERR("Error: flow queue create failed.\n");
1288  exit(EXIT_FAILURE);
1289  }
1290 
1291  gbl_args->fqueue[i][j] = queue;
1292  }
1293  }
1294 
1295  memset(thread_tbl, 0, sizeof(thread_tbl));
1296 
1297  stats = gbl_args->stats;
1298 
1299  odp_barrier_init(&gbl_args->barrier, num_workers + 1);
1300 
1301  /* Create worker threads */
1302  odph_thread_common_param_init(&thr_common);
1303  thr_common.instance = instance;
1304  thr_common.cpumask = &cpumask;
1305 
1306  for (i = 0; i < num_workers; ++i) {
1307  gbl_args->thread[i].stats = &stats[i];
1308 
1309  odph_thread_param_init(&thr_param[i]);
1310  thr_param[i].start = run_worker;
1311  thr_param[i].arg = &gbl_args->thread[i];
1312  thr_param[i].thr_type = ODP_THREAD_WORKER;
1313  }
1314 
1315  odph_thread_create(thread_tbl, &thr_common, thr_param, num_workers);
1316 
1317  /* Start packet receive and transmit */
1318  for (i = 0; i < if_count; ++i) {
1319  odp_pktio_t pktio;
1320 
1321  pktio = gbl_args->pktios[i].pktio;
1322  ret = odp_pktio_start(pktio);
1323  if (ret) {
1324  ODPH_ERR("Error: unable to start %s\n",
1325  gbl_args->appl.if_names[i]);
1326  exit(EXIT_FAILURE);
1327  }
1328  }
1329 
1330  ret = print_speed_stats(num_workers, stats, gbl_args->appl.time,
1331  gbl_args->appl.accuracy);
1332 
1333  /* Stop receiving new packet */
1334  for (i = 0; i < if_count; i++)
1335  odp_pktio_stop(gbl_args->pktios[i].pktio);
1336 
1337  odp_atomic_store_u32(&gbl_args->exit_threads, 1);
1338 
1339  /* Master thread waits for other threads to exit */
1340  odph_thread_join(thread_tbl, num_workers);
1341 
1342  for (i = 0; i < if_count; i++) {
1343  odp_pktio_close(gbl_args->pktios[i].pktio);
1344 
1345  for (j = 0; j < gbl_args->appl.num_flows; j++)
1346  odp_queue_destroy(gbl_args->fqueue[i][j]);
1347  }
1348 
1349  free(gbl_args->appl.if_names);
1350  free(gbl_args->appl.if_str);
1351 
1352  if (odp_pool_destroy(pool)) {
1353  ODPH_ERR("Error: pool destroy\n");
1354  exit(EXIT_FAILURE);
1355  }
1356 
1357  if (odp_shm_free(shm)) {
1358  ODPH_ERR("Error: shm free\n");
1359  exit(EXIT_FAILURE);
1360  }
1361 
1362  if (odp_term_local()) {
1363  ODPH_ERR("Error: term local\n");
1364  exit(EXIT_FAILURE);
1365  }
1366 
1367  if (odp_term_global(instance)) {
1368  ODPH_ERR("Error: term global\n");
1369  exit(EXIT_FAILURE);
1370  }
1371 
1372  return ret;
1373 }
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
void odp_barrier_init(odp_barrier_t *barr, int count)
Initialize barrier with thread count.
void odp_barrier_wait(odp_barrier_t *barr)
Synchronize thread execution on barrier.
#define ODP_ALIGNED_CACHE
Defines type/struct/variable to be cache line size aligned.
#define odp_unlikely(x)
Branch unlikely taken.
Definition: spec/hints.h:64
uint16_t odp_be_to_cpu_16(odp_u16be_t be16)
Convert 16bit big endian to cpu native uint16_t.
uint32_t odp_be_to_cpu_32(odp_u32be_t be32)
Convert 32bit big endian to cpu native uint32_t.
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_free(odp_event_t event)
Free event.
#define ODP_EVENT_INVALID
Invalid event.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
#define ODP_STATIC_ASSERT(cond, msg)
Compile time assertion macro.
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.
int odp_pktin_event_queue(odp_pktio_t pktio, odp_queue_t queues[], int num)
Event queues for packet input.
odp_pktio_t odp_pktio_open(const char *name, odp_pool_t pool, const odp_pktio_param_t *param)
Open a packet IO interface.
int odp_pktio_config(odp_pktio_t pktio, const odp_pktio_config_t *config)
Configure packet IO interface options.
void odp_pktio_print(odp_pktio_t pktio)
Print pktio info to the console.
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.
odp_pktio_op_mode_t
Packet IO operation mode.
uint64_t odp_pktio_to_u64(odp_pktio_t pktio)
Get printable value for an odp_pktio_t.
int odp_pktin_queue_config(odp_pktio_t pktio, const odp_pktin_queue_param_t *param)
Configure packet input queues.
int odp_pktout_queue_config(odp_pktio_t pktio, const odp_pktout_queue_param_t *param)
Configure packet output queues.
@ ODP_PKTIO_OP_MT
Multithread safe operation.
@ ODP_PKTIN_MODE_SCHED
Packet input through scheduler and scheduled event queues.
uint32_t odp_packet_seg_len(odp_packet_t pkt)
Packet data length following the data pointer.
void odp_packet_prefetch(odp_packet_t pkt, uint32_t offset, uint32_t len)
Packet data prefetch.
void * odp_packet_data(odp_packet_t pkt)
Packet data pointer.
int odp_packet_has_eth(odp_packet_t pkt)
Check for Ethernet header.
void * odp_packet_user_area(odp_packet_t pkt)
User area address.
uint32_t odp_packet_len(odp_packet_t pkt)
Packet data length.
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.
odp_pktio_t odp_packet_input(odp_packet_t pkt)
Packet input interface.
@ ODP_PROTO_LAYER_L2
Layer L2 protocols (Ethernet, VLAN, etc)
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
int odp_pool_capability(odp_pool_capability_t *capa)
Query pool capabilities.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
void odp_pool_print(odp_pool_t pool)
Print pool info.
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_PACKET
Packet pool.
int odp_queue_context_set(odp_queue_t queue, void *context, uint32_t len)
Set queue context.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#define ODP_QUEUE_INVALID
Invalid queue.
#define ODP_QUEUE_NAME_LEN
Maximum queue name length, including the null character.
void * odp_queue_context(odp_queue_t queue)
Get queue context.
int odp_queue_enq(odp_queue_t queue, odp_event_t ev)
Enqueue an event to a 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.
@ 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.
void odp_schedule_config_init(odp_schedule_config_t *config)
Initialize schedule configuration options.
#define ODP_SCHED_SYNC_ATOMIC
Atomic queue synchronization.
#define ODP_SCHED_SYNC_ORDERED
Ordered queue synchronization.
void odp_schedule_order_unlock(uint32_t lock_index)
Release ordered context lock.
#define ODP_SCHED_NO_WAIT
Do not wait.
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.
int odp_schedule_capability(odp_schedule_capability_t *capa)
Query scheduler capabilities.
odp_event_t odp_schedule(odp_queue_t *from, uint64_t wait)
Schedule an event.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
void odp_schedule_order_lock(uint32_t lock_index)
Acquire ordered context lock.
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.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
The OpenDataPlane API.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
Packet input queue parameters.
uint32_t num_queues
Number of input queues to be created.
odp_pktio_op_mode_t op_mode
Operation mode.
odp_queue_param_t queue_param
Queue parameters.
odp_pktin_hash_proto_t hash_proto
Protocol field selection for hashing.
odp_bool_t hash_enable
Enable flow hashing.
odp_pktio_set_op_t set_op
Supported set operations.
uint32_t max_input_queues
Maximum number of input queues.
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.
odp_pktio_op_mode_t op_mode
Operation mode.
uint32_t num_queues
Number of output queues to be created.
struct odp_pool_capability_t::@122 pkt
Packet pool capabilities
uint32_t max_num
Maximum number of buffers of any size.
Pool parameters.
uint32_t uarea_size
Minimum user area size in bytes.
uint32_t num
Number of buffers in the pool.
odp_pool_type_t type
Pool type.
uint32_t len
Minimum length of 'num' packets.
uint32_t seg_len
Minimum number of packet data bytes that can be stored in the first segment of a newly allocated pack...
struct odp_pool_param_t::@126 pkt
Parameters for packet pools.
ODP Queue parameters.
odp_schedule_param_t sched
Scheduler parameters.
uint32_t size
Queue size.
odp_queue_type_t type
Queue type.
uint32_t context_len
Queue context data length.
void * context
Queue context pointer.
uint32_t max_ordered_locks
Maximum number of ordered locks per queue.
Schedule configuration.
uint32_t queue_size
Maximum number of events required to be stored simultaneously in scheduled queue.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
uint32_t lock_count
Ordered lock count for this queue.
odp_schedule_sync_t sync
Synchronization method.
uint32_t ipv4_udp
IPv4 addresses and UDP port numbers.
struct odp_pktin_hash_proto_t::@99 proto
Protocol header fields for hashing.
struct odp_pktio_set_op_t::@104 op
Operation flags.
uint32_t promisc_mode
Promiscuous mode.