API Reference Manual 1.51.0
Loading...
Searching...
No Matches
odp_classifier.c
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2015-2018 Linaro Limited
3 * Copyright (c) 2019-2026 Nokia
4 * Copyright (c) 2020 Marvell
5 */
6
15#ifndef _GNU_SOURCE
16#define _GNU_SOURCE
17#endif
18
19#include <stdlib.h>
20#include <string.h>
21#include <getopt.h>
22#include <unistd.h>
23#include <inttypes.h>
24#include <signal.h>
25
26#include <odp_api.h>
27#include <odp/helper/odph_api.h>
28
29#include <strings.h>
30#include <errno.h>
31#include <stdio.h>
32
36#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
37
41#define MAX_PKT_BURST 64
42
46#define DEF_PKT_BURST 32
47
51#define SHM_PKT_POOL_SIZE 10000
52
56#define SHM_PKT_POOL_BUF_SIZE 1856
57
61#define MAX_PMR_COUNT 32
62
66#define DISPLAY_STRING_LEN 32
67
69#define MAX_VAL_SIZE 16
70
72#define NO_PATH(file_name) (strrchr((file_name), '/') ? \
73 strrchr((file_name), '/') + 1 : (file_name))
74
75typedef struct {
76 odp_queue_t queue;
77 odp_pool_t pool;
78 odp_cos_t cos;
79 odp_pmr_t pmr;
80 odp_atomic_u64_t queue_pkt_count;
81 odp_atomic_u64_t pool_pkt_count;
82 char cos_name[ODP_COS_NAME_LEN];
83 char src_cos_name[ODP_COS_NAME_LEN];
84 struct {
86 uint8_t value_be[MAX_VAL_SIZE];
87 uint8_t mask_be[MAX_VAL_SIZE];
88 uint32_t val_sz;
89 uint32_t offset;
90 } rule;
91 char value[DISPLAY_STRING_LEN];
92 char mask[DISPLAY_STRING_LEN];
93 int has_src_cos;
94} global_statistics;
95
96typedef struct {
97 char cos_name[ODP_COS_NAME_LEN];
98 uint64_t count;
99} ci_pass_counters;
100
101typedef struct {
102 char cos_name[ODP_COS_NAME_LEN];
103 odp_aggr_enq_profile_t cos_enq_prof;
105 odp_schedule_prio_t q_prio;
106 odp_schedule_sync_t q_sync;
107 uint32_t num_aggr;
108} cos_q_param_t;
109
110typedef struct {
111 odp_pktout_queue_t pktout[MAX_WORKERS];
112 int num_pktout;
113 global_statistics stats[MAX_PMR_COUNT];
114 ci_pass_counters ci_pass_rules[MAX_PMR_COUNT];
115 cos_q_param_t cos_q_param[MAX_PMR_COUNT];
116 int policy_count;
117 int num_ci_pass_rules;
118 int num_cos_q_param;
119 int appl_mode;
120 odp_atomic_u64_t total_packets;
121 unsigned int cpu_count;
122 uint32_t time;
123 char *if_name;
124 int shutdown;
125 int shutdown_sig;
126 int verbose;
127 int promisc_mode;
128 int classifier_enable;
129 int parse_layer;
130 int cos_pools;
131 int pool_size;
132 int burst_size;
133 uint32_t vector_size;
134 odp_spinlock_t verbose_lock;
135} appl_args_t;
136
137enum packet_mode {
138 APPL_MODE_DROP,
139 APPL_MODE_REPLY
140};
141
142static appl_args_t *appl_args_gbl;
143
144static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len);
145static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len);
146static int parse_args(int argc, char *argv[], appl_args_t *appl_args);
147static void print_info(char *progname, appl_args_t *appl_args);
148static void usage(void);
149
150static inline int check_ci_pass_count(appl_args_t *args)
151{
152 int i, j;
153 uint64_t count;
154
155 if (args->num_ci_pass_rules == 0)
156 return 0;
157
158 for (i = 0; i < args->num_ci_pass_rules; i++) {
159 for (j = 0; j < args->policy_count; j++) {
160 if (!strcmp(args->stats[j].cos_name,
161 args->ci_pass_rules[i].cos_name)) {
162 count = odp_atomic_load_u64(&args->stats[i].queue_pkt_count);
163 if (args->ci_pass_rules[i].count > count) {
164 ODPH_ERR("Error: Cos = %s, expected packets = %" PRIu64 ","
165 "received packet = %" PRIu64 "\n",
166 args->stats[j].cos_name,
167 args->ci_pass_rules[i].count, count);
168 return -1;
169 }
170 break;
171 }
172 }
173 if (j == args->policy_count) {
174 ODPH_ERR("Error: invalid Cos:%s specified for CI pass count\n",
175 args->ci_pass_rules[i].cos_name);
176 return -1;
177 }
178 }
179 return 0;
180}
181
182static inline void print_cls_statistics(appl_args_t *args)
183{
184 int i;
185 uint32_t timeout;
186 int infinite = 0;
187
188 printf("\n");
189 for (i = 0; i < 40; i++)
190 printf("-");
191 printf("\n");
192 /* print statistics */
193 printf("CLASSIFIER EXAMPLE STATISTICS\n");
194 for (i = 0; i < 40; i++)
195 printf("-");
196 printf("\n");
197 printf("CONFIGURATION\n");
198 printf("\n");
199 printf("COS\tVALUE\t\tMASK\n");
200 for (i = 0; i < 40; i++)
201 printf("-");
202 printf("\n");
203 for (i = 0; i < args->policy_count - 1; i++) {
204 printf("%s\t", args->stats[i].cos_name);
205 printf("%s\t", args->stats[i].value);
206 printf("%s\n", args->stats[i].mask);
207 }
208 printf("\n");
209 printf("RECEIVED PACKETS\n");
210 for (i = 0; i < 40; i++)
211 printf("-");
212 printf("\n");
213 for (i = 0; i < args->policy_count; i++)
214 printf("%-12s |", args->stats[i].cos_name);
215 printf("%-6s %-6s", "Total", "Mpps");
216 printf("\n");
217 for (i = 0; i < args->policy_count; i++)
218 printf("%-6s %-6s|", "queue", "pool");
219 printf("\n");
220
221 timeout = args->time;
222
223 /* Incase if default value is given for timeout
224 run the loop infinitely */
225 if (timeout == 0)
226 infinite = 1;
227
228 uint64_t total_packets, last_total_packets = 0;
229 odp_time_t start = odp_time_local(), end;
230 float mpps;
231
232 for (; timeout > 0 || infinite; timeout--) {
233 sleep(1);
234 for (i = 0; i < args->policy_count; i++) {
235 printf("%-6" PRIu64 " ",
236 odp_atomic_load_u64(&args->stats[i]
237 .queue_pkt_count));
238 printf("%-6" PRIu64 "|",
239 odp_atomic_load_u64(&args->stats[i]
240 .pool_pkt_count));
241 }
242
243 end = odp_time_local();
244 total_packets = odp_atomic_load_u64(&args->total_packets);
245 mpps = (total_packets - last_total_packets) /
246 (odp_time_diff_ns(end, start) / 1000.0);
247 printf("%-6" PRIu64 " %-6.3f\n", total_packets, mpps);
248 last_total_packets = total_packets;
249 start = end;
250
251 if (args->shutdown_sig)
252 break;
253 }
254
255 printf("\n");
256}
257
258static int parse_custom(const char *str, uint8_t *buf_be, int max_size)
259{
260 int i, len;
261
262 /* hex string without 0x prefix */
263 len = strlen(str);
264 if (len > 2 * max_size)
265 return -1;
266
267 for (i = 0; i < len; i += 2)
268 if (sscanf(&str[i], "%2" SCNx8, &buf_be[i / 2]) != 1)
269 return -1;
270
271 return len / 2;
272}
273
283static odp_pktio_t create_pktio(const char *dev, odp_pool_t pool)
284{
285 odp_pktio_t pktio;
286 odp_pktio_param_t pktio_param;
287 odp_pktin_queue_param_t pktin_param;
290 odp_pktout_queue_param_t pktout_queue_param;
291 int num_tx;
292
293 odp_pktio_param_init(&pktio_param);
294 pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
295
296 /* Open a packet IO instance */
297 pktio = odp_pktio_open(dev, pool, &pktio_param);
298 if (pktio == ODP_PKTIO_INVALID) {
299 ODPH_ERR("pktio create failed for %s\n", dev);
300 exit(EXIT_FAILURE);
301 }
302
303 if (odp_pktio_capability(pktio, &capa)) {
304 ODPH_ERR("pktio capability failed for %s\n", dev);
305 exit(EXIT_FAILURE);
306 }
307
308 odp_pktin_queue_param_init(&pktin_param);
309 pktin_param.classifier_enable = appl_args_gbl->classifier_enable;
310
311 if (odp_pktin_queue_config(pktio, &pktin_param)) {
312 ODPH_ERR("pktin queue config failed for %s\n", dev);
313 exit(EXIT_FAILURE);
314 }
315
316 num_tx = appl_args_gbl->cpu_count;
317
318 if (num_tx > (int)capa.max_output_queues) {
319 printf("Sharing %i output queues between %i workers\n",
320 capa.max_output_queues, num_tx);
321 num_tx = capa.max_output_queues;
322 }
323
324 appl_args_gbl->num_pktout = num_tx;
325
326 odp_pktout_queue_param_init(&pktout_queue_param);
327 pktout_queue_param.num_queues = num_tx;
328
329 if (odp_pktout_queue_config(pktio, &pktout_queue_param)) {
330 ODPH_ERR("pktout queue config failed for %s\n", dev);
331 exit(EXIT_FAILURE);
332 }
333
334 if (odp_pktout_queue(pktio, appl_args_gbl->pktout, num_tx) != num_tx) {
335 ODPH_ERR("Pktout queue query failed: %s\n", dev);
336 exit(EXIT_FAILURE);
337 }
338
339 if (appl_args_gbl->promisc_mode && odp_pktio_promisc_mode(pktio) != 1) {
340 if (!capa.set_op.op.promisc_mode) {
341 ODPH_ERR("enabling promisc mode not supported %s\n", dev);
342 exit(EXIT_FAILURE);
343 }
344
345 if (odp_pktio_promisc_mode_set(pktio, true)) {
346 ODPH_ERR("failed to enable promisc mode for %s\n", dev);
347 exit(EXIT_FAILURE);
348 }
349 }
350
351 printf("created pktio:%" PRIu64 ", dev:%s", odp_pktio_to_u64(pktio), dev);
352
353 odph_ethaddr_t mac;
354
355 if (odp_pktio_mac_addr(pktio, &mac, sizeof(mac)) == sizeof(mac)) {
356 printf(", mac");
357 for (int c = 0; c < (int)sizeof(mac); c++)
358 printf(":%02x", mac.addr[c]);
359 }
360
361 printf("\n");
362
364 cfg.parser.layer = appl_args_gbl->parse_layer;
365 if (odp_pktio_config(pktio, &cfg)) {
366 ODPH_ERR("failed to configure pktio %s\n", dev);
367 exit(EXIT_FAILURE);
368 }
369
370 return pktio;
371}
372
373static void process_packets(odp_packet_t pkts[], int num, odp_queue_t in_q,
374 odp_pktout_queue_t out_q, appl_args_t *appl, int thr,
375 odp_bool_t was_vector)
376{
377 odp_pool_t pool;
378 int i, j, dropped, sent;
379 global_statistics *stats;
380 unsigned long err_cnt = 0;
381 /* Per-thread batch counter identifying packets processed by a thread in this processing
382 * round */
383 static __thread uint64_t batch;
384
385 if (odp_unlikely(appl->verbose)) {
386 odp_queue_info_t info;
387 const char *qname = odp_queue_info(in_q, &info) == 0 ? info.name : "(unknown)";
388 const char *orig = was_vector ? "vector" : "packet";
389
390 odp_spinlock_lock(&appl->verbose_lock);
391
392 for (j = 0; j < num; j++) {
393 uint32_t len = odp_packet_len(pkts[j]);
394
395 printf("Queue: %s, origin: %s, thread: %d, batch: %" PRIu64 "\n", qname,
396 orig, thr, batch);
397
398 if (len > 96)
399 len = 96;
400
401 odp_packet_print_data(pkts[j], 0, len);
402 }
403
404 ++batch;
405 odp_spinlock_unlock(&appl->verbose_lock);
406 }
407
408 /* Total packets received */
409 odp_atomic_add_u64(&appl->total_packets, num);
410
411 /* Drop packets with errors */
412 dropped = drop_err_pkts(pkts, num);
413 if (odp_unlikely(dropped)) {
414 num -= dropped;
415 err_cnt += dropped;
416 ODPH_ERR("Drop frame - err_cnt:%lu\n", err_cnt);
417 }
418
419 for (j = 0; j < num; j++) {
420 pool = odp_packet_pool(pkts[j]);
421
422 for (i = 0; i < MAX_PMR_COUNT; i++) {
423 stats = &appl->stats[i];
424 if (in_q == stats->queue)
425 odp_atomic_inc_u64(&stats->queue_pkt_count);
426 if (pool == stats->pool)
427 odp_atomic_inc_u64(&stats->pool_pkt_count);
428 }
429 }
430
431 if (appl->appl_mode == APPL_MODE_DROP) {
432 odp_packet_free_multi(pkts, num);
433 return;
434 }
435
436 /* Swap Eth MACs and possibly IP-addrs before sending back */
437 swap_pkt_addrs(pkts, num);
438
439 sent = odp_pktout_send(out_q, pkts, num);
440 sent = sent < 0 ? 0 : sent;
441
442 if (sent != num) {
443 ODPH_ERR(" [%i] Packet send failed\n", thr);
444 odp_packet_free_multi(pkts + sent, num - sent);
445 }
446}
447
452static int pktio_receive_thread(void *arg)
453{
454 const int thr = odp_thread_id();
455 odp_packet_t single_pkts[MAX_PKT_BURST];
456 odp_event_t ev, evs[MAX_PKT_BURST], *ev_tbl;
457 odp_event_type_t type;
459 int num_recv, num_pkts, vector_size;
460 odp_queue_t queue;
461 appl_args_t *appl = (appl_args_t *)arg;
462 const uint64_t wait_time = odp_schedule_wait_time(100 * ODP_TIME_MSEC_IN_NS);
463 odp_pktout_queue_t pktout = appl_args_gbl->pktout[thr % appl_args_gbl->num_pktout];
464
465 /* Loop packets */
466 for (;;) {
467 if (appl->shutdown)
468 break;
469
470 /* Use schedule to get buf from any input queue */
471 num_recv = odp_schedule_multi(&queue, wait_time, evs, appl_args_gbl->burst_size);
472
473 /* Loop back to receive packets incase of invalid event */
474 if (odp_unlikely(!num_recv))
475 continue;
476
477 num_pkts = 0;
478
479 for (int i = 0; i < num_recv; i++) {
480 ev = evs[i];
481 type = odp_event_type(ev);
482
483 if (type == ODP_EVENT_VECTOR) {
485 vector_size = odp_event_vector_tbl(evv, &ev_tbl);
486
487 odp_packet_t vector_pkts[vector_size];
488
489 odp_packet_from_event_multi(vector_pkts, ev_tbl, vector_size);
490 process_packets(vector_pkts, vector_size, queue, pktout, appl, thr,
491 true);
493 continue;
494 } else if (type == ODP_EVENT_PACKET) {
495 single_pkts[num_pkts++] = odp_packet_from_event(ev);
496 } else {
497 ODPH_ERR("Unexpected event received, type: %d, freeing\n", type);
498 odp_event_free(ev);
499 }
500 }
501
502 if (num_pkts > 0)
503 process_packets(single_pkts, num_pkts, queue, pktout, appl, thr, false);
504 }
505
506 return 0;
507}
508
509static odp_pool_t create_vector_pool(appl_args_t *args)
510{
511 /* For now, singleton pool */
512 static odp_pool_t pool = ODP_POOL_INVALID;
513 odp_pool_param_t param;
514
515 if (pool != ODP_POOL_INVALID)
516 return pool;
517
518 odp_pool_param_init(&param);
519 param.event_vector.num = args->pool_size;
520 param.event_vector.max_size = args->vector_size;
522 pool = odp_pool_create("vector_pool", &param);
523
524 if (pool == ODP_POOL_INVALID) {
525 ODPH_ERR("Error: failed to create event vector pool\n");
526 exit(EXIT_FAILURE);
527 }
528
529 printf("created singleton event vector pool: %" PRIu64 ", size: %u, vector size: %u\n",
530 odp_pool_to_u64(pool), args->pool_size, args->vector_size);
531
532 return pool;
533}
534
535static void destroy_vector_pool(odp_pool_t pool)
536{
537 /* Destroy the singleton pool once */
538 static odp_bool_t is_destroyed;
539
540 if (is_destroyed)
541 return;
542
543 odp_pool_destroy(pool);
544 is_destroyed = true;
545}
546
547static odp_pool_t pool_create(const char *name)
548{
549 static odp_pool_t pool = ODP_POOL_INVALID;
550 odp_pool_param_t pool_params;
551
552 if (!appl_args_gbl->cos_pools && pool != ODP_POOL_INVALID)
553 return pool;
554
555 odp_pool_param_init(&pool_params);
556 pool_params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
557 pool_params.pkt.len = SHM_PKT_POOL_BUF_SIZE;
558 pool_params.pkt.num = appl_args_gbl->pool_size;
559 pool_params.type = ODP_POOL_PACKET;
560 pool = odp_pool_create(name, &pool_params);
561
562 if (pool == ODP_POOL_INVALID) {
563 ODPH_ERR("Error: failed to create pool %s\n", name);
564 exit(EXIT_FAILURE);
565 }
566
567 return pool;
568}
569
570static odp_cos_t configure_default_cos(odp_pktio_t pktio, appl_args_t *args)
571{
572 odp_queue_param_t qparam;
573 const char *queue_name = "DefaultQueue";
574 const char *pool_name = "DefaultPool";
575 const char *cos_name = "DefaultCos";
576 odp_queue_t queue_default;
577 odp_pool_t pool_default;
578 odp_cos_t cos_default;
579 odp_cls_cos_param_t cls_param;
580 global_statistics *stats = args->stats;
581
582
583 odp_queue_param_init(&qparam);
584 qparam.type = ODP_QUEUE_TYPE_SCHED;
587 queue_default = odp_queue_create(queue_name, &qparam);
588 if (queue_default == ODP_QUEUE_INVALID) {
589 ODPH_ERR("Error: default queue create failed\n");
590 exit(EXIT_FAILURE);
591 }
592
593 pool_default = pool_create(pool_name);
594
595 odp_cls_cos_param_init(&cls_param);
596 cls_param.pool = pool_default;
597 cls_param.queue = queue_default;
598
599 cos_default = odp_cls_cos_create(cos_name, &cls_param);
600
601 if (cos_default == ODP_COS_INVALID) {
602 ODPH_ERR("Error: default cos create failed\n");
603 exit(EXIT_FAILURE);
604 }
605
606 if (0 > odp_pktio_default_cos_set(pktio, cos_default)) {
607 ODPH_ERR("odp_pktio_default_cos_set failed\n");
608 exit(EXIT_FAILURE);
609 }
610 stats[args->policy_count].cos = cos_default;
611 /* add default queue to global stats */
612 stats[args->policy_count].queue = queue_default;
613 if (appl_args_gbl->cos_pools)
614 stats[args->policy_count].pool = pool_default;
615 snprintf(stats[args->policy_count].cos_name,
616 sizeof(stats[args->policy_count].cos_name),
617 "%s", cos_name);
618 odp_atomic_init_u64(&stats[args->policy_count].queue_pkt_count, 0);
619 odp_atomic_init_u64(&stats[args->policy_count].pool_pkt_count, 0);
620 args->policy_count++;
621 return cos_default;
622}
623
624static cos_q_param_t *find_cos_q_param(appl_args_t *args, const char *name)
625{
626 int i;
627
628 for (i = 0; i < args->num_cos_q_param; i++) {
629 if (strcmp(args->cos_q_param[i].cos_name, name) == 0)
630 return &args->cos_q_param[i];
631 }
632
633 return NULL;
634}
635
636static int find_cos(appl_args_t *args, const char *name, odp_cos_t *cos)
637{
638 global_statistics *stats;
639 int i;
640
641 for (i = 0; i < args->policy_count - 1; i++) {
642 stats = &args->stats[i];
643
644 if (strcmp(stats->cos_name, name) == 0) {
645 *cos = stats->cos;
646 return 0;
647 }
648 }
649
650 return -1;
651}
652
653static void configure_cos(odp_cos_t default_cos, appl_args_t *args)
654{
655 char cos_name[ODP_COS_NAME_LEN];
656 char pool_name[ODP_POOL_NAME_LEN];
657 const char *queue_name;
658 odp_cls_cos_param_t cls_param;
659 int i;
660 cos_q_param_t *cq_param;
661 global_statistics *stats;
662 odp_queue_param_t qparam;
663
664 for (i = 0; i < args->policy_count - 1; i++) {
665 stats = &args->stats[i];
666 queue_name = stats->cos_name;
667 odp_queue_param_init(&qparam);
668 qparam.type = ODP_QUEUE_TYPE_SCHED;
670 odp_cls_cos_param_init(&cls_param);
671 cq_param = find_cos_q_param(args, queue_name);
672
673 if (cq_param != NULL) {
674 qparam.sched.sync = cq_param->q_sync;
675 qparam.sched.prio = cq_param->q_prio;
676 qparam.num_aggr = cq_param->num_aggr;
677 qparam.aggr = &cq_param->q_aggr;
678 cls_param.aggr_enq_profile = cq_param->cos_enq_prof;
679 } else {
681 }
682
683 stats->queue = odp_queue_create(queue_name, &qparam);
684 if (ODP_QUEUE_INVALID == stats->queue) {
685 ODPH_ERR("odp_queue_create failed\n");
686 exit(EXIT_FAILURE);
687 }
688
689 snprintf(pool_name, sizeof(pool_name), "%sPool%d",
690 args->stats[i].cos_name, i);
691
692 snprintf(cos_name, sizeof(cos_name), "CoS%s",
693 stats->cos_name);
694 cls_param.pool = pool_create(pool_name);
695 if (appl_args_gbl->cos_pools)
696 stats->pool = cls_param.pool;
697
698 if (cq_param != NULL && cq_param->num_aggr > 0)
699 cls_param.queue = odp_queue_aggr(stats->queue, 0);
700 else
701 cls_param.queue = stats->queue;
702
703 stats->cos = odp_cls_cos_create(cos_name, &cls_param);
704
705 if (ODP_COS_INVALID == stats->cos) {
706 ODPH_ERR("odp_cls_cos_create failed\n");
707 exit(EXIT_FAILURE);
708 }
709
710 odp_atomic_init_u64(&stats->queue_pkt_count, 0);
711 odp_atomic_init_u64(&stats->pool_pkt_count, 0);
712 }
713
714 for (i = 0; i < args->policy_count - 1; i++) {
715 odp_pmr_param_t pmr_param;
716 odp_cos_t src_cos = default_cos;
717
718 stats = &args->stats[i];
719
720 if (stats->has_src_cos) {
721 if (find_cos(args, stats->src_cos_name, &src_cos)) {
722 ODPH_ERR("find_cos failed\n");
723 exit(EXIT_FAILURE);
724 }
725 }
726
727 odp_cls_pmr_param_init(&pmr_param);
728 pmr_param.term = stats->rule.term;
729 pmr_param.match.value = stats->rule.value_be;
730 pmr_param.match.mask = stats->rule.mask_be;
731 pmr_param.val_sz = stats->rule.val_sz;
732 pmr_param.offset = stats->rule.offset;
733
734 stats->pmr = odp_cls_pmr_create(&pmr_param, 1, src_cos,
735 stats->cos);
736 if (stats->pmr == ODP_PMR_INVALID) {
737 ODPH_ERR("odp_pktio_pmr_cos failed\n");
738 exit(EXIT_FAILURE);
739 }
740 }
741
742}
743
744static void sig_handler(int signo)
745{
746 (void)signo;
747
748 if (appl_args_gbl == NULL)
749 return;
750 appl_args_gbl->shutdown_sig = 1;
751}
752
756int main(int argc, char *argv[])
757{
758 odph_helper_options_t helper_options;
759 odph_thread_t thread_tbl[MAX_WORKERS];
760 odp_pool_t pool;
761 int num_workers;
762 int i;
763 odp_cpumask_t cpumask;
764 char cpumaskstr[ODP_CPUMASK_STR_SIZE];
765 odp_pktio_t pktio;
766 appl_args_t *args;
767 odp_cos_t default_cos;
768 odp_shm_t shm;
769 int ret;
770 odp_instance_t instance;
771 odp_init_t init_param;
772 odph_thread_common_param_t thr_common;
773 odph_thread_param_t thr_param;
774
775 signal(SIGINT, sig_handler);
776
777 /* Let helper collect its own arguments (e.g. --odph_proc) */
778 argc = odph_parse_options(argc, argv);
779 if (odph_options(&helper_options)) {
780 ODPH_ERR("Error: reading ODP helper options failed\n");
781 exit(EXIT_FAILURE);
782 }
783
784 odp_init_param_init(&init_param);
785 init_param.mem_model = helper_options.mem_model;
786
787 /* Init ODP before calling anything else */
788 if (odp_init_global(&instance, &init_param, NULL)) {
789 ODPH_ERR("Error: ODP global init failed\n");
790 exit(EXIT_FAILURE);
791 }
792
793 /* Init this thread */
794 if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
795 ODPH_ERR("Error: ODP local init failed\n");
796 exit(EXIT_FAILURE);
797 }
798
799 /* Reserve memory for args from shared mem */
800 shm = odp_shm_reserve("cls_shm_args", sizeof(appl_args_t),
801 ODP_CACHE_LINE_SIZE, 0);
802
803 if (shm == ODP_SHM_INVALID) {
804 ODPH_ERR("Error: shared mem reserve failed\n");
805 exit(EXIT_FAILURE);
806 }
807
808 args = odp_shm_addr(shm);
809
810 if (args == NULL) {
811 ODPH_ERR("Error: shared mem alloc failed\n");
812 exit(EXIT_FAILURE);
813 }
814
815 appl_args_gbl = args;
816 memset(args, 0, sizeof(*args));
817 odp_spinlock_init(&args->verbose_lock);
818 /* Parse and store the application arguments */
819 if (parse_args(argc, argv, args))
820 goto args_error;
821
822 /* Print both system and application information */
823 print_info(NO_PATH(argv[0]), args);
824
825 num_workers = MAX_WORKERS;
826 if (args->cpu_count && args->cpu_count < MAX_WORKERS)
827 num_workers = args->cpu_count;
828
829 /* Get default worker cpumask */
830 num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
831 (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
832
833 printf("num worker threads: %i\n", num_workers);
834 printf("first CPU: %i\n", odp_cpumask_first(&cpumask));
835 printf("cpu mask: %s\n", cpumaskstr);
836
837 /* Create packet pool */
838 pool = pool_create("packet_pool");
839
840 for (i = 0; i < args->num_cos_q_param; i++) {
841 if (args->cos_q_param[i].num_aggr > 0)
842 args->cos_q_param[i].q_aggr.pool = create_vector_pool(args);
843 }
844
845 /* Configure scheduler */
847
848 /* odp_pool_print(pool); */
849 odp_atomic_init_u64(&args->total_packets, 0);
850
851 /* create pktio per interface */
852 pktio = create_pktio(args->if_name, pool);
853
854 /* configure default Cos */
855 default_cos = configure_default_cos(pktio, args);
856
857 configure_cos(default_cos, args);
858
859 printf("\n");
863
864 if (odp_pktio_start(pktio)) {
865 ODPH_ERR("Error: unable to start pktio\n");
866 exit(EXIT_FAILURE);
867 }
868
869 /* Create and init worker threads */
870 memset(thread_tbl, 0, sizeof(thread_tbl));
871 odph_thread_common_param_init(&thr_common);
872 odph_thread_param_init(&thr_param);
873
874 thr_param.start = pktio_receive_thread;
875 thr_param.arg = args;
876 thr_param.thr_type = ODP_THREAD_WORKER;
877
878 thr_common.instance = instance;
879 thr_common.cpumask = &cpumask;
880 thr_common.share_param = 1;
881
882 odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers);
883
884 if (args->verbose == 0) {
885 print_cls_statistics(args);
886 } else {
887 int timeout = args->time;
888
889 for (i = 0; timeout == 0 || i < timeout; i++) {
890 if (args->shutdown_sig)
891 break;
892
893 sleep(1);
894 }
895 }
896
897 odp_pktio_stop(pktio);
898 args->shutdown = 1;
899 odph_thread_join(thread_tbl, num_workers);
900
901 if (check_ci_pass_count(args)) {
902 ODPH_ERR("Error: Packet count verification failed\n");
903 exit(EXIT_FAILURE);
904 }
905
906 for (i = 0; i < args->policy_count; i++) {
907 if ((i != args->policy_count - 1) &&
908 odp_cls_pmr_destroy(args->stats[i].pmr))
909 ODPH_ERR("err: odp_cls_pmr_destroy for %d\n", i);
910 if (odp_cos_destroy(args->stats[i].cos))
911 ODPH_ERR("err: odp_cos_destroy for %d\n", i);
912 if (odp_queue_destroy(args->stats[i].queue))
913 ODPH_ERR("err: odp_queue_destroy for %d\n", i);
914 if (args->cos_pools && odp_pool_destroy(args->stats[i].pool))
915 ODPH_ERR("err: odp_pool_destroy for %d\n", i);
916 }
917
918 if (odp_pktio_close(pktio))
919 ODPH_ERR("err: close pktio error\n");
920
921 for (i = 0; i < args->num_cos_q_param; i++) {
922 cos_q_param_t *cos_q_param = &args->cos_q_param[i];
923
924 if (cos_q_param->q_aggr.pool != ODP_POOL_INVALID)
925 destroy_vector_pool(cos_q_param->q_aggr.pool);
926 }
927
928 if (odp_pool_destroy(pool))
929 ODPH_ERR("err: odp_pool_destroy error\n");
930
931 free(args->if_name);
932
933args_error:
934 odp_shm_free(shm);
935
936 ret = odp_term_local();
937 if (ret)
938 ODPH_ERR("odp_term_local error %d\n", ret);
939 ret = odp_term_global(instance);
940 if (ret)
941 ODPH_ERR("odp_term_global error %d\n", ret);
942 printf("Exit\n\n");
943 return ret;
944}
945
957static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len)
958{
959 odp_packet_t pkt;
960 unsigned i, j;
961 int dropped = 0;
962
963 for (i = 0, j = 0; i < len; ++i) {
964 pkt = pkt_tbl[i];
965
967 odp_packet_free(pkt); /* Drop */
968 dropped++;
969 } else if (odp_unlikely(i != j++)) {
970 pkt_tbl[j-1] = pkt;
971 }
972 }
973
974 return dropped;
975}
976
983static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len)
984{
985 odp_packet_t pkt;
986 odph_ethhdr_t *eth;
987 odph_ethaddr_t tmp_addr;
988 odph_ipv4hdr_t *ip;
989 odp_u32be_t ip_tmp_addr; /* tmp ip addr */
990 unsigned i;
991
992 for (i = 0; i < len; ++i) {
993 pkt = pkt_tbl[i];
994 if (odp_packet_has_eth(pkt)) {
995 eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL);
996
997 tmp_addr = eth->dst;
998 eth->dst = eth->src;
999 eth->src = tmp_addr;
1000
1001 if (odp_packet_has_ipv4(pkt)) {
1002 /* IPv4 */
1003 ip = (odph_ipv4hdr_t *)
1004 odp_packet_l3_ptr(pkt, NULL);
1005
1006 ip_tmp_addr = ip->src_addr;
1007 ip->src_addr = ip->dst_addr;
1008 ip->dst_addr = ip_tmp_addr;
1009 }
1010 }
1011 }
1012}
1013
1014static int convert_str_to_pmr_enum(char *token, odp_cls_pmr_term_t *term)
1015{
1016 if (NULL == token)
1017 return -1;
1018
1019 if (strcasecmp(token, "ODP_PMR_ETHTYPE_0") == 0) {
1020 *term = ODP_PMR_ETHTYPE_0;
1021 return 0;
1022 } else if (strcasecmp(token, "ODP_PMR_ETHTYPE_X") == 0) {
1023 *term = ODP_PMR_ETHTYPE_X;
1024 return 0;
1025 } else if (strcasecmp(token, "ODP_PMR_VLAN_ID_0") == 0) {
1026 *term = ODP_PMR_VLAN_ID_0;
1027 return 0;
1028 } else if (strcasecmp(token, "ODP_PMR_VLAN_ID_X") == 0) {
1029 *term = ODP_PMR_VLAN_ID_X;
1030 return 0;
1031 } else if (strcasecmp(token, "ODP_PMR_UDP_DPORT") == 0) {
1032 *term = ODP_PMR_UDP_DPORT;
1033 return 0;
1034 } else if (strcasecmp(token, "ODP_PMR_TCP_DPORT") == 0) {
1035 *term = ODP_PMR_TCP_DPORT;
1036 return 0;
1037 } else if (strcasecmp(token, "ODP_PMR_UDP_SPORT") == 0) {
1038 *term = ODP_PMR_UDP_SPORT;
1039 return 0;
1040 } else if (strcasecmp(token, "ODP_PMR_TCP_SPORT") == 0) {
1041 *term = ODP_PMR_TCP_SPORT;
1042 return 0;
1043 } else if (strcasecmp(token, "ODP_PMR_DIP_ADDR") == 0) {
1044 *term = ODP_PMR_DIP_ADDR;
1045 return 0;
1046 } else if (strcasecmp(token, "ODP_PMR_SIP_ADDR") == 0) {
1047 *term = ODP_PMR_SIP_ADDR;
1048 return 0;
1049 } else if (strcasecmp(token, "ODP_PMR_DMAC") == 0) {
1050 *term = ODP_PMR_DMAC;
1051 return 0;
1052 } else if (strcasecmp(token, "ODP_PMR_CUSTOM_FRAME") == 0) {
1053 *term = ODP_PMR_CUSTOM_FRAME;
1054 return 0;
1055 } else if (strcasecmp(token, "ODP_PMR_CUSTOM_L3") == 0) {
1056 *term = ODP_PMR_CUSTOM_L3;
1057 return 0;
1058 }
1059
1060 return -1;
1061}
1062
1063static int parse_pmr_policy(appl_args_t *appl_args, char *optarg)
1064{
1065 int policy_count;
1066 char *token, *cos0, *cos1, *cur_char;
1067 size_t len;
1068 odp_cls_pmr_term_t term;
1069 global_statistics *stats;
1070 odph_ethaddr_t mac;
1071 char *pmr_str;
1072 uint32_t offset, ip_addr, u32;
1073 unsigned long int value, mask;
1074 uint16_t u16;
1075 int val_sz, mask_sz;
1076
1077 policy_count = appl_args->policy_count;
1078 stats = appl_args->stats;
1079
1080 /* last array index is needed for default queue */
1081 if (policy_count >= MAX_PMR_COUNT - 1) {
1082 ODPH_ERR("Too many policies. Max count is %i.\n",
1083 MAX_PMR_COUNT - 1);
1084 return -1;
1085 }
1086
1087 len = strlen(optarg);
1088 len++;
1089 pmr_str = malloc(len);
1090 if (pmr_str == NULL) {
1091 ODPH_ERR("Memory allocation failed\n");
1092 return -1;
1093 }
1094 strcpy(pmr_str, optarg);
1095
1096 /* PMR TERM */
1097 /* <term>:<xxx>:<yyy>:<src_cos>:<dst_cos> */
1098 token = strtok(pmr_str, ":");
1099 if (convert_str_to_pmr_enum(token, &term)) {
1100 ODPH_ERR("Invalid ODP_PMR_TERM string\n");
1101 goto error;
1102 }
1103 stats[policy_count].rule.term = term;
1104 stats[policy_count].rule.offset = 0;
1105
1106 /* PMR value */
1107 switch (term) {
1108 case ODP_PMR_ETHTYPE_0:
1109 /* Fall through */
1110 case ODP_PMR_ETHTYPE_X:
1111 /* Fall through */
1112 /* :<type>:<mask> */
1113 case ODP_PMR_VLAN_ID_0:
1114 /* Fall through */
1115 case ODP_PMR_VLAN_ID_X:
1116 /* Fall through */
1117 /* :<vlan_id>:<mask> */
1118 case ODP_PMR_UDP_DPORT:
1119 /* Fall through */
1120 case ODP_PMR_TCP_DPORT:
1121 /* Fall through */
1122 case ODP_PMR_UDP_SPORT:
1123 /* Fall through */
1124 case ODP_PMR_TCP_SPORT:
1125 /* :<port>:<mask> */
1126 token = strtok(NULL, ":");
1127 odph_strcpy(stats[policy_count].value, token,
1128 DISPLAY_STRING_LEN);
1129 value = strtoul(token, NULL, 0);
1130 u16 = value;
1131 u16 = odp_cpu_to_be_16(u16);
1132 memcpy(stats[policy_count].rule.value_be, &u16, sizeof(u16));
1133
1134 token = strtok(NULL, ":");
1135 odph_strcpy(stats[policy_count].mask, token,
1136 DISPLAY_STRING_LEN);
1137 mask = strtoul(token, NULL, 0);
1138 u16 = mask;
1139 u16 = odp_cpu_to_be_16(u16);
1140 memcpy(stats[policy_count].rule.mask_be, &u16, sizeof(u16));
1141
1142 stats[policy_count].rule.val_sz = 2;
1143 break;
1144 case ODP_PMR_DIP_ADDR:
1145 /* Fall through */
1146 case ODP_PMR_SIP_ADDR:
1147 /* :<IP addr>:<mask> */
1148 token = strtok(NULL, ":");
1149 odph_strcpy(stats[policy_count].value, token,
1150 DISPLAY_STRING_LEN);
1151
1152 if (odph_ipv4_addr_parse(&ip_addr, token)) {
1153 ODPH_ERR("Bad IP address\n");
1154 goto error;
1155 }
1156
1157 u32 = odp_cpu_to_be_32(ip_addr);
1158 memcpy(stats[policy_count].rule.value_be, &u32, sizeof(u32));
1159
1160 token = strtok(NULL, ":");
1161 odph_strcpy(stats[policy_count].mask, token,
1162 DISPLAY_STRING_LEN);
1163 mask = strtoul(token, NULL, 0);
1164 u32 = mask;
1165 u32 = odp_cpu_to_be_32(u32);
1166 memcpy(stats[policy_count].rule.mask_be, &u32, sizeof(u32));
1167
1168 stats[policy_count].rule.val_sz = 4;
1169 break;
1170 case ODP_PMR_DMAC:
1171 /* :<MAC addr>:<mask> */
1172 token = strtok(NULL, ":");
1173 odph_strcpy(stats[policy_count].value, token,
1174 DISPLAY_STRING_LEN);
1175
1176 /* Replace hyphens in the MAC string with colons to be compatible with
1177 * odph_eth_addr_parse(). */
1178 cur_char = token;
1179 while ((cur_char = strchr(cur_char, '-')) != NULL)
1180 *cur_char++ = ':';
1181
1182 if (odph_eth_addr_parse(&mac, token)) {
1183 ODPH_ERR("Invalid MAC address. Use format 11-22-33-44-55-66.\n");
1184 goto error;
1185 }
1186
1187 memcpy(stats[policy_count].rule.value_be, mac.addr, ODPH_ETHADDR_LEN);
1188 stats[policy_count].rule.val_sz = 6;
1189
1190 token = strtok(NULL, ":");
1191 odph_strcpy(stats[policy_count].mask, token, DISPLAY_STRING_LEN);
1192 mask_sz = parse_custom(token, stats[policy_count].rule.mask_be, ODPH_ETHADDR_LEN);
1193 if (mask_sz != ODPH_ETHADDR_LEN) {
1194 ODPH_ERR("Invalid mask. Provide mask without 0x prefix.\n");
1195 goto error;
1196 }
1197 break;
1199 /* Fall through */
1200 case ODP_PMR_CUSTOM_L3:
1201 /* :<offset>:<value>:<mask> */
1202 token = strtok(NULL, ":");
1203 errno = 0;
1204 offset = strtoul(token, NULL, 0);
1205 stats[policy_count].rule.offset = offset;
1206 if (errno)
1207 goto error;
1208
1209 token = strtok(NULL, ":");
1210 odph_strcpy(stats[policy_count].value, token,
1211 DISPLAY_STRING_LEN);
1212 val_sz = parse_custom(token,
1213 stats[policy_count].rule.value_be,
1214 MAX_VAL_SIZE);
1215 stats[policy_count].rule.val_sz = val_sz;
1216 if (val_sz <= 0)
1217 goto error;
1218
1219 token = strtok(NULL, ":");
1220 odph_strcpy(stats[policy_count].mask, token,
1221 DISPLAY_STRING_LEN);
1222 mask_sz = parse_custom(token,
1223 stats[policy_count].rule.mask_be,
1224 MAX_VAL_SIZE);
1225 if (mask_sz != val_sz)
1226 goto error;
1227 break;
1228 default:
1229 goto error;
1230 }
1231
1232 /* Optional source CoS name and name of this CoS
1233 * :<src_cos>:<cos> */
1234 cos0 = strtok(NULL, ":");
1235 cos1 = strtok(NULL, ":");
1236 if (cos0 == NULL)
1237 goto error;
1238
1239 if (cos1) {
1240 stats[policy_count].has_src_cos = 1;
1241 odph_strcpy(stats[policy_count].src_cos_name, cos0,
1243 odph_strcpy(stats[policy_count].cos_name, cos1,
1245 } else {
1246 odph_strcpy(stats[policy_count].cos_name, cos0,
1248 }
1249
1250 appl_args->policy_count++;
1251 free(pmr_str);
1252 return 0;
1253
1254error:
1255 free(pmr_str);
1256 return -1;
1257}
1258
1259static int parse_cos_q_param(appl_args_t *appl_args, char *optarg)
1260{
1261 char *tmp_str = strdup(optarg), *tmp;
1262 cos_q_param_t *cos_q_param;
1263 int ret = 0;
1264
1265 if (tmp_str == NULL)
1266 ODPH_ABORT("Failed to allocate memory, aborting.\n");
1267
1268 if (appl_args->num_cos_q_param >= MAX_PMR_COUNT) {
1269 ODPH_ERR("Too many queue CoS configurations. Max count is %i.\n", MAX_PMR_COUNT);
1270 ret = -1;
1271 goto out;
1272 }
1273
1274 cos_q_param = &appl_args->cos_q_param[appl_args->num_cos_q_param];
1275 cos_q_param->q_aggr.pool = ODP_POOL_INVALID;
1276 tmp = strtok(tmp_str, ":");
1277
1278 if (tmp == NULL) {
1279 ODPH_ERR("CoS queue name missing.\n");
1280 ret = -1;
1281 goto out;
1282 }
1283
1284 if (find_cos_q_param(appl_args, tmp) != NULL) {
1285 printf("Warning: duplicate CoS queue parameter entry for \"%s\", skipping.\n",
1286 tmp);
1287 goto out;
1288 }
1289
1290 odph_strcpy(cos_q_param->cos_name, tmp, ODP_COS_NAME_LEN);
1291 tmp = strtok(NULL, ":");
1292
1293 if (tmp == NULL) {
1294 ODPH_ERR("CoS queue priority missing.\n");
1295 ret = -1;
1296 goto out;
1297 }
1298
1299 cos_q_param->q_prio = strcmp(tmp, "default") == 0 ?
1300 odp_schedule_default_prio() : atoi(tmp);
1301 tmp = strtok(NULL, ":");
1302
1303 if (tmp == NULL) {
1304 ODPH_ERR("CoS queue synchronization type missing.\n");
1305 ret = -1;
1306 goto out;
1307 }
1308
1309 if (strcmp(tmp, "ODP_SCHED_SYNC_PARALLEL") == 0) {
1310 cos_q_param->q_sync = ODP_SCHED_SYNC_PARALLEL;
1311 } else if (strcmp(tmp, "ODP_SCHED_SYNC_ATOMIC") == 0) {
1312 cos_q_param->q_sync = ODP_SCHED_SYNC_ATOMIC;
1313 } else if (strcmp(tmp, "ODP_SCHED_SYNC_ORDERED") == 0) {
1314 cos_q_param->q_sync = ODP_SCHED_SYNC_ORDERED;
1315 } else {
1316 ODPH_ERR("Invalid queue synchronization type: \"%s\".\n", tmp);
1317 ret = -1;
1318 goto out;
1319 }
1320
1321 tmp = strtok(NULL, ":");
1322
1323 if (tmp == NULL) {
1324 ODPH_ERR("CoS queue aggregator enqueue profile type missing.\n");
1325 ret = -1;
1326 goto out;
1327 }
1328
1329 if (strcmp(tmp, "ODP_AEP_TYPE_NONE") == 0) {
1330 cos_q_param->cos_enq_prof.type = ODP_AEP_TYPE_NONE;
1331 } else if (strcmp(tmp, "ODP_AEP_TYPE_IPV4_FRAG") == 0) {
1332 cos_q_param->cos_enq_prof.type = ODP_AEP_TYPE_IPV4_FRAG;
1333 } else if (strcmp(tmp, "ODP_AEP_TYPE_IPV6_FRAG") == 0) {
1334 cos_q_param->cos_enq_prof.type = ODP_AEP_TYPE_IPV6_FRAG;
1335 } else if (strcmp(tmp, "ODP_AEP_TYPE_CUSTOM") == 0) {
1336 cos_q_param->cos_enq_prof.type = ODP_AEP_TYPE_CUSTOM;
1337 tmp = strtok(NULL, ":");
1338
1339 if (tmp == NULL) {
1340 ODPH_ERR("Custom aggregator enqueue profile param missing.\n");
1341 ret = -1;
1342 goto out;
1343 }
1344
1345 cos_q_param->cos_enq_prof.param = (uintptr_t)strtoll(tmp, NULL, 16);
1346 } else {
1347 ODPH_ERR("Invalid queue aggregator enqueue profile type: \"%s\".\n", tmp);
1348 ret = -1;
1349 goto out;
1350 }
1351
1352 tmp = strtok(NULL, ":");
1353
1354 if (tmp != NULL) {
1355 cos_q_param->q_aggr.max_tmo_ns = atoll(tmp);
1356 tmp = strtok(NULL, ":");
1357
1358 if (tmp == NULL) {
1359 ODPH_ERR("Malformed aggregator parameter format.\n");
1360 ret = -1;
1361 goto out;
1362 }
1363
1364 cos_q_param->q_aggr.max_size = atoi(tmp);
1365 cos_q_param->q_aggr.event_type = ODP_EVENT_PACKET;
1366 cos_q_param->num_aggr = 1;
1367 }
1368
1369 appl_args->num_cos_q_param++;
1370 appl_args->vector_size = ODPH_MAX(appl_args->vector_size, cos_q_param->q_aggr.max_size);
1371
1372out:
1373 free(tmp_str);
1374
1375 return ret;
1376}
1377
1378static int check_cos_q_param_policies(appl_args_t *appl_args)
1379{
1380 int j;
1381
1382 for (int i = 0; i < appl_args->num_cos_q_param; i++) {
1383 const char *cq_name = appl_args->cos_q_param[i].cos_name;
1384
1385 for (j = 0; j < appl_args->policy_count; j++) {
1386 if (strcmp(appl_args->stats[j].cos_name, cq_name) == 0)
1387 break;
1388 }
1389
1390 if (j == appl_args->policy_count) {
1391 ODPH_ERR("No matching policy found for cos_queue_param \"%s\"\n", cq_name);
1392 return -1;
1393 }
1394 }
1395
1396 return 0;
1397}
1398
1399static int parse_policy_ci_pass_count(appl_args_t *appl_args, char *optarg)
1400{
1401 int num_ci_pass_rules;
1402 char *token, *value;
1403 size_t len;
1404 ci_pass_counters *ci_pass_rules;
1405 char *count_str;
1406
1407 num_ci_pass_rules = appl_args->num_ci_pass_rules;
1408 ci_pass_rules = appl_args->ci_pass_rules;
1409
1410 /* last array index is needed for default queue */
1411 if (num_ci_pass_rules >= MAX_PMR_COUNT) {
1412 ODPH_ERR("Too many ci pass counters. Max count is %i.\n",
1413 MAX_PMR_COUNT);
1414 return -1;
1415 }
1416
1417 len = strlen(optarg);
1418 len++;
1419 count_str = malloc(len);
1420 if (count_str == NULL) {
1421 ODPH_ERR("Memory allocation failed\n");
1422 return -1;
1423 }
1424 strcpy(count_str, optarg);
1425
1426 token = strtok(count_str, ":");
1427 value = strtok(NULL, ":");
1428 if (!token || !value) {
1429 free(count_str);
1430 return -1;
1431 }
1432 odph_strcpy(ci_pass_rules[num_ci_pass_rules].cos_name, token, ODP_COS_NAME_LEN);
1433 ci_pass_rules[num_ci_pass_rules].count = atoll(value);
1434 appl_args->num_ci_pass_rules++;
1435 free(count_str);
1436 return 0;
1437}
1438
1446static int parse_args(int argc, char *argv[], appl_args_t *appl_args)
1447{
1448 int opt;
1449 size_t len;
1450 int i;
1451 int interface = 0;
1452 int ret = 0;
1453
1454 static const struct option longopts[] = {
1455 {"count", required_argument, NULL, 'c'},
1456 {"interface", required_argument, NULL, 'i'},
1457 {"policy", required_argument, NULL, 'p'},
1458 {"cos_queue_param", required_argument, NULL, 'q'},
1459 {"mode", required_argument, NULL, 'm'},
1460 {"time", required_argument, NULL, 't'},
1461 {"ci_pass", required_argument, NULL, 'C'},
1462 {"promisc_mode", no_argument, NULL, 'P'},
1463 {"verbose", no_argument, NULL, 'v'},
1464 {"help", no_argument, NULL, 'h'},
1465 {"enable", required_argument, NULL, 'e'},
1466 {"layer", required_argument, NULL, 'l'},
1467 {"dedicated", required_argument, NULL, 'd'},
1468 {"size", required_argument, NULL, 's'},
1469 {"burst", required_argument, NULL, 'b'},
1470 {NULL, 0, NULL, 0}
1471 };
1472
1473 static const char *shortopts = "+c:t:i:p:q:m:t:C:Pvhe:l:d:s:b:";
1474
1475 appl_args->cpu_count = 1; /* Use one worker by default */
1476 appl_args->verbose = 0;
1477 appl_args->promisc_mode = 0;
1478 appl_args->classifier_enable = 1;
1479 appl_args->parse_layer = ODP_PROTO_LAYER_ALL;
1480 appl_args->cos_pools = 1;
1481 appl_args->pool_size = SHM_PKT_POOL_SIZE;
1482 appl_args->burst_size = DEF_PKT_BURST;
1483
1484 while (ret == 0) {
1485 opt = getopt_long(argc, argv, shortopts,
1486 longopts, NULL);
1487
1488 if (opt == -1)
1489 break; /* No more options */
1490
1491 switch (opt) {
1492 case 'c':
1493 appl_args->cpu_count = atoi(optarg);
1494 break;
1495 case 'p':
1496 if (parse_pmr_policy(appl_args, optarg)) {
1497 ret = -1;
1498 break;
1499 }
1500 break;
1501 case 'q':
1502 if (parse_cos_q_param(appl_args, optarg)) {
1503 ret = -1;
1504 break;
1505 }
1506 break;
1507 case 't':
1508 appl_args->time = atoi(optarg);
1509 break;
1510 case 'i':
1511 len = strlen(optarg);
1512 if (len == 0) {
1513 ret = -1;
1514 break;
1515 }
1516 len += 1; /* add room for '\0' */
1517
1518 appl_args->if_name = malloc(len);
1519 if (appl_args->if_name == NULL) {
1520 ret = -1;
1521 break;
1522 }
1523
1524 strcpy(appl_args->if_name, optarg);
1525 interface = 1;
1526 break;
1527 case 'm':
1528 i = atoi(optarg);
1529 if (i == 0)
1530 appl_args->appl_mode = APPL_MODE_DROP;
1531 else
1532 appl_args->appl_mode = APPL_MODE_REPLY;
1533 break;
1534 case 'C':
1535 if (parse_policy_ci_pass_count(appl_args, optarg)) {
1536 ret = -1;
1537 break;
1538 }
1539 break;
1540 case 'P':
1541 appl_args->promisc_mode = 1;
1542 break;
1543 case 'v':
1544 appl_args->verbose = 1;
1545 break;
1546 case 'h':
1547 ret = -1;
1548 break;
1549 case 'e':
1550 appl_args->classifier_enable = atoi(optarg);
1551 break;
1552 case 'l':
1553 appl_args->parse_layer = atoi(optarg);
1554 break;
1555 case 'd':
1556 appl_args->cos_pools = atoi(optarg);
1557 break;
1558 case 's':
1559 appl_args->pool_size = atoi(optarg);
1560 break;
1561 case 'b':
1562 appl_args->burst_size = atoi(optarg);
1563 break;
1564 default:
1565 break;
1566 }
1567 }
1568
1569 if (!interface)
1570 ret = -1;
1571
1572 if (appl_args->if_name == NULL)
1573 ret = -1;
1574
1575 if (!ret && check_cos_q_param_policies(appl_args))
1576 ret = -1;
1577
1578 if (ret) {
1579 usage();
1580 free(appl_args->if_name);
1581 }
1582
1583 /* reset optind from the getopt lib */
1584 optind = 1;
1585
1586 return ret;
1587}
1588
1592static void print_info(char *progname, appl_args_t *appl_args)
1593{
1595
1596 printf("Running ODP appl: \"%s\"\n"
1597 "-----------------\n"
1598 "Using IF: %s\n",
1599 progname, appl_args->if_name);
1600 printf("Promisc mode: %s\n", appl_args->promisc_mode ? "enabled" : "disabled");
1601 printf("\n\n");
1602 fflush(NULL);
1603}
1604
1608static void usage(void)
1609{
1610 printf("\n"
1611 "ODP Classifier example.\n"
1612 "Usage: odp_classifier OPTIONS\n"
1613 " E.g. odp_classifier -i eth1 -m 0 -p \"ODP_PMR_SIP_ADDR:10.10.10.0:0xFFFFFF00:queue1\" \\\n"
1614 " -p \"ODP_PMR_SIP_ADDR:10.10.10.10:0xFFFFFFFF:queue1:queue2\" \\\n"
1615 " -q \"queue1:1:ODP_SCHED_SYNC_PARALLEL:ODP_AEP_TYPE_NONE\" \\\n"
1616 " -q \"queue2:3:ODP_SCHED_SYNC_ATOMIC:ODP_AEP_TYPE_CUSTOM:1234:0:4\"\n"
1617 "\n"
1618 "The above example would classify:\n"
1619 " 1) Packets from source IP address 10.10.10.0/24 to queue1, except ...\n"
1620 " 2) Packets from source IP address 10.10.10.10 to queue2\n"
1621 " 3) All other packets to DefaultCos\n"
1622 "\n"
1623 "Mandatory OPTIONS:\n"
1624 " -i, --interface <interface name>\n"
1625 "\n"
1626 "Optional OPTIONS\n"
1627 " -p, --policy <PMR term>:<offset>:<value>:<mask>:<src queue>:<dst queue>\n"
1628 "\n"
1629 " <PMR term> PMR term name defined in odp_cls_pmr_term_t\n"
1630 " <offset> If term is ODP_PMR_CUSTOM_FRAME or _CUSTOM_L3, offset in bytes is used\n"
1631 " <value> PMR value to be matched\n"
1632 " <mask> PMR mask bits to be applied on the PMR value.\n"
1633 " CUSTOM PMR terms accept plain hex string, other PMR terms require\n"
1634 " hex string with '0x' prefix.\n"
1635 " <src queue> Optional name of the source queue (CoS). The default CoS is used when\n"
1636 " this is not defined.\n"
1637 " <dst queue> Name of the destination queue (CoS).\n"
1638 "\n"
1639 " -q, --cos_queue_param <name>:<queue prio>:<queue sync>:<cos enqueue profile type>:<optional custom value>:<optional tmo ns>:<optional size>\n"
1640 "\n"
1641 " <name> Configuration for a queue (CoS) defined with '--policy' 'dst queue'.\n"
1642 " <queue prio> CoS queue priority. Use priority value or \"default\" for default priority.\n"
1643 " <queue sync> CoS queue synchronization. Use ODP_SCHED_SYNC_PARALLEL,\n"
1644 " ODP_SCHED_SYNC_ATOMIC or ODP_SCHED_SYNC_ORDERED.\n"
1645 " <cos enqueue profile type>\n"
1646 " Aggregator enqueue profile type for CoS. Use odp_aggr_enq_profile_t::type\n"
1647 " names.\n"
1648 " <optional custom value>\n"
1649 " If ODP_AEP_TYPE_CUSTOM aggregator enqueue profile was used,\n"
1650 " pass a hex value (without '0x') for odp_aggr_enq_profile_t::param.\n"
1651 " <optional tmo ns>\n"
1652 " Aggregator configuration parameter timeout in nanoseconds. Optional,\n"
1653 " if not passed, aggregation for queue disabled.\n"
1654 " <optional size>\n"
1655 " Aggregator configuration parameter vector size. Mandatory if 'optional tmo ns'\n"
1656 " passed, optional otherwise.\n"
1657 "\n");
1658 printf(" -c, --count <num> CPU count, 0=all available, default=1\n"
1659 "\n"
1660 " -m, --mode <mode> 0: Packet Drop mode. Received packets will be dropped\n"
1661 " !0: Echo mode. Received packets will be sent back\n"
1662 " default: Packet Drop mode\n"
1663 "\n"
1664 " -t, --time <sec> !0: Time for which the classifier will be run in seconds\n"
1665 " 0: Runs in infinite loop\n"
1666 " default: Runs in infinite loop\n"
1667 "\n"
1668 " -e, --enable <enable> 0: Classifier is disabled\n"
1669 " 1: Classifier is enabled\n"
1670 " default: Classifier is enabled\n"
1671 "\n"
1672 " -l, --layer <layer> Parse packets up to and including this layer. See odp_proto_layer_t\n"
1673 " default: ODP_PROTO_LAYER_ALL\n"
1674 "\n"
1675 " -d, --dedicated <enable> 0: One pool for pktio and all CoSes\n"
1676 " 1: Dedicated pools for pktio and each CoS\n"
1677 " default: Dedicated pools\n"
1678 "\n"
1679 " -s, --size <num> Number of packets in each packet pool\n"
1680 " default: %d\n"
1681 "\n"
1682 " -b, --burst <num> Packet burst size\n"
1683 " default: %d\n"
1684 "\n"
1685 " -C, --ci_pass <dst queue:count>\n"
1686 " Minimum acceptable packet count for a CoS destination queue.\n"
1687 " If the received packet count is smaller than this value,\n"
1688 " the application will exit with an error.\n"
1689 " E.g: -C \"queue1:100\" -C \"queue2:200\" -C \"DefaultQueue:100\"\n"
1690 " -P, --promisc_mode Enable promiscuous mode.\n"
1691 " -v, --verbose Verbose output.\n"
1692 " -h, --help Display help and exit.\n"
1693 "\n", SHM_PKT_POOL_SIZE, DEF_PKT_BURST);
1694}
void odp_atomic_init_u64(odp_atomic_u64_t *atom, uint64_t val)
Initialize atomic uint64 variable.
void odp_atomic_inc_u64(odp_atomic_u64_t *atom)
Increment atomic uint64 variable.
void odp_atomic_add_u64(odp_atomic_u64_t *atom, uint64_t val)
Add to atomic uint64 variable.
uint64_t odp_atomic_load_u64(odp_atomic_u64_t *atom)
Load value of atomic uint64 variable.
#define ODP_COS_NAME_LEN
Maximum class of service name length, including the null character.
int odp_cos_destroy(odp_cos_t cos)
Discard a class-of-service along with all its associated resources.
odp_pmr_t odp_cls_pmr_create(const odp_pmr_param_t *terms, int num_terms, odp_cos_t src_cos, odp_cos_t dst_cos)
Create Packet Matching Rule (PMR)
odp_cls_pmr_term_t
Packet Matching Rule terms.
#define ODP_PMR_INVALID
Invalid packet matching rule handle.
void odp_cls_print_all(void)
Print classifier info.
int odp_cls_pmr_destroy(odp_pmr_t pmr)
Function to destroy a packet match rule.
#define ODP_COS_INVALID
Invalid class of service handle.
odp_cos_t odp_cls_cos_create(const char *name, const odp_cls_cos_param_t *param)
Create a class-of-service.
void odp_cls_cos_param_init(odp_cls_cos_param_t *param)
Initialize class of service parameters.
void odp_cls_pmr_param_init(odp_pmr_param_t *param)
Initialize packet matching rule parameters.
@ ODP_PMR_TCP_DPORT
Destination TCP port (val_sz = 2)
@ ODP_PMR_ETHTYPE_0
Initial (outer) Ethertype only (val_sz = 2)
@ ODP_PMR_SIP_ADDR
Source IPv4 address (val_sz = 4)
@ ODP_PMR_DIP_ADDR
Destination IPv4 address (val_sz = 4)
@ ODP_PMR_TCP_SPORT
Source TCP port (val_sz = 2)
@ ODP_PMR_VLAN_ID_X
Last (most inner) VLAN ID (val_sz = 2)
@ ODP_PMR_CUSTOM_FRAME
Custom frame match rule.
@ ODP_PMR_UDP_SPORT
Source UDP port (val_sz = 2)
@ ODP_PMR_VLAN_ID_0
First (outer) VLAN ID (val_sz = 2)
@ ODP_PMR_UDP_DPORT
Destination UDP port (val_sz = 2)
@ ODP_PMR_DMAC
Destination MAC address (val_sz = 6)
@ ODP_PMR_ETHTYPE_X
Ethertype of most inner VLAN tag (val_sz = 2)
@ ODP_PMR_CUSTOM_L3
Custom layer 3 match rule.
#define odp_unlikely(x)
Branch unlikely taken.
Definition spec/hints.h:64
uint32_t odp_u32be_t
unsigned 32bit big endian
odp_u16be_t odp_cpu_to_be_16(uint16_t cpu16)
Convert cpu native uint16_t to 16bit big endian.
odp_u32be_t odp_cpu_to_be_32(uint32_t cpu32)
Convert cpu native uint32_t to 32bit big endian.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
int odp_cpumask_first(const odp_cpumask_t *mask)
Find first set CPU in mask.
int32_t odp_cpumask_to_str(const odp_cpumask_t *mask, char *str, int32_t size)
Format a string from CPU mask.
#define ODP_CPUMASK_STR_SIZE
The maximum number of characters needed to record any CPU mask as a string (output of odp_cpumask_to_...
void odp_event_vector_free(odp_event_vector_t evv)
Free event vector.
odp_event_vector_t odp_event_vector_from_event(odp_event_t ev)
Get event vector handle from event.
uint32_t odp_event_vector_tbl(odp_event_vector_t evv, odp_event_t **event_tbl)
Get event vector table.
void odp_event_free(odp_event_t event)
Free event.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
odp_event_type_t
Event type.
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.
void odp_spinlock_lock(odp_spinlock_t *splock)
Acquire spin lock.
void odp_spinlock_init(odp_spinlock_t *splock)
Initialize spin lock.
void odp_spinlock_unlock(odp_spinlock_t *splock)
Release spin lock.
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)
Set interface 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_l3_ptr(odp_packet_t pkt, uint32_t *len)
Layer 3 start pointer.
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_free_multi(const odp_packet_t pkt[], int num)
Free multiple packets.
odp_pool_t odp_packet_pool(odp_packet_t pkt)
Packet pool.
@ ODP_PROTO_LAYER_ALL
All layers.
uint64_t odp_pool_to_u64(odp_pool_t hdl)
Get printable value for an odp_pool_t.
#define ODP_POOL_NAME_LEN
Maximum pool name length, including the null character.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
void odp_pool_print_all(void)
Print debug info about all pools.
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_PACKET
Packet pool.
@ ODP_POOL_EVENT_VECTOR
Event vector pool.
odp_queue_t odp_queue_aggr(odp_queue_t queue, uint32_t aggr_index)
Get a queue handle of an event aggregator associated with a queue.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#define ODP_QUEUE_INVALID
Invalid queue.
void odp_queue_print_all(void)
Print debug info about all queues.
odp_queue_t odp_queue_create(const char *name, const odp_queue_param_t *param)
Queue create.
int odp_queue_destroy(odp_queue_t queue)
Destroy ODP queue.
int odp_queue_info(odp_queue_t queue, odp_queue_info_t *info)
Retrieve information about a queue.
@ ODP_QUEUE_TYPE_SCHED
Scheduled queue.
int odp_schedule_sync_t
Scheduler synchronization method.
#define ODP_SCHED_SYNC_PARALLEL
Parallel scheduled queues.
int odp_schedule_prio_t
Scheduling priority level.
int odp_schedule_multi(odp_queue_t *from, uint64_t wait, odp_event_t events[], int num)
Schedule multiple events.
#define ODP_SCHED_SYNC_ATOMIC
Atomic queue synchronization.
#define ODP_SCHED_SYNC_ORDERED
Ordered queue synchronization.
int odp_schedule_default_prio(void)
Default scheduling priority level.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
uint64_t odp_schedule_wait_time(uint64_t ns)
Schedule wait time.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
int odp_shm_free(odp_shm_t shm)
Free a contiguous block of shared memory.
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.
int odp_thread_id(void)
Get thread identifier.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
odp_time_t odp_time_local(void)
Current local time.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1)
Time difference in nanoseconds.
The OpenDataPlane API.
Dummy type for strong typing.
Event aggregator enqueuing profile.
Class of service parameters Used to communicate class of service creation options.
odp_queue_t queue
Mapping used when num_queue = 1, hashing is disabled in this case and application has to configure th...
odp_aggr_enq_profile_t aggr_enq_profile
Event aggregator enqueuing profile.
odp_pool_t pool
Pool associated with CoS.
Event vector configuration.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
Packet input queue parameters.
odp_bool_t classifier_enable
Enable classifier.
odp_pktio_set_op_t set_op
Supported set operations.
uint32_t max_output_queues
Maximum number of output queues.
Packet IO configuration options.
odp_pktio_parser_config_t parser
Packet input parser configuration.
Packet IO parameters.
odp_pktin_mode_t in_mode
Packet input mode.
odp_proto_layer_t layer
Protocol parsing level in packet input.
Packet output queue parameters.
uint32_t num_queues
Number of output queues to be created.
Packet Matching Rule parameter structure.
uint32_t offset
Offset to the value.
uint32_t val_sz
Size of the value to be matched.
struct odp_pmr_param_t::@4::@6 match
Parameters for single-valued matches.
const void * value
Points to the value to be matched.
const void * mask
Mask of the bits to be matched.
odp_cls_pmr_term_t term
Packet Matching Rule term.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@139 pkt
Parameters for packet pools.
struct odp_pool_param_t::@142 event_vector
Parameters for event vector pools.
odp_pool_type_t type
Pool type.
uint32_t len
Minimum length of 'num' packets.
uint32_t max_size
Maximum number of handles (such as odp_packet_t) in a vector.
uint32_t seg_len
Minimum number of packet data bytes that can be stored in the first segment of a newly allocated pack...
Queue information.
const char * name
Queue name.
ODP Queue parameters.
odp_schedule_param_t sched
Scheduler parameters.
odp_queue_type_t type
Queue type.
const odp_event_aggr_config_t * aggr
Event aggregator configuration parameters.
uint32_t num_aggr
Number of event aggregators.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.
struct odp_pktio_set_op_t::@112 op
Operation flags.
uint32_t promisc_mode
Promiscuous mode.