API Reference Manual 1.51.0
Loading...
Searching...
No Matches
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
96ODP_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
121typedef enum pktin_mode_t {
122 SCHED_ORDERED = 0,
123 SCHED_ATOMIC,
124 SCHED_PARALLEL
125} pktin_mode_t;
126
130typedef 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
149typedef struct {
150 odp_bool_t input_queue;
151 uint64_t idx;
152 uint64_t seq[MAX_FLOWS];
153} qcontext_t;
154
158typedef 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;
166ODP_STATIC_ASSERT(sizeof(flow_t) <= PKT_UAREA_SIZE,
167 "Flow data doesn't fit in the packet user area\n");
168
172typedef 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
190typedef 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
203typedef struct {
204 odph_ethhdr_t *eth;
205 odph_ipv4hdr_t *ipv4;
206 odph_udphdr_t *udp;
207} packet_hdr_t;
208
212typedef struct thread_args_t {
213 stats_t *stats;
214} thread_args_t;
215
219typedef 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
253static args_t *gbl_args;
254
260static 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
287static 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
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
326static 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
349static 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
372static 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
387static 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
438static 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
515static 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
579static 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
724static 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
787static 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
803static 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
814static 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
854static 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
1035static 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
1062static 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
1080int 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;
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.
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.
void * odp_packet_user_area(odp_packet_t pkt)
User area address.
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.
void * odp_queue_context(odp_queue_t queue)
Get queue context.
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.
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.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
#define ODP_SHM_INVALID
Invalid shared memory block.
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.
uint32_t max_num
Maximum number of buffers of any size.
struct odp_pool_capability_t::@134 pkt
Packet pool capabilities
uint32_t uarea_size
Minimum user area size in bytes.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@139 pkt
Parameters for packet pools.
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...
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.
struct odp_pktin_hash_proto_t::@107 proto
Protocol header fields for hashing.
uint32_t ipv4_udp
IPv4 addresses and UDP port numbers.
struct odp_pktio_set_op_t::@112 op
Operation flags.
uint32_t promisc_mode
Promiscuous mode.