examples/pipeline: support hash functions
[dpdk.git] / examples / pipeline / cli.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <rte_common.h>
11 #include <rte_ethdev.h>
12 #include <rte_swx_port_ethdev.h>
13 #include <rte_swx_port_ring.h>
14 #include <rte_swx_port_source_sink.h>
15 #include <rte_swx_port_fd.h>
16 #include <rte_swx_pipeline.h>
17 #include <rte_swx_ctl.h>
18
19 #include "cli.h"
20
21 #include "obj.h"
22 #include "thread.h"
23
24 #ifndef CMD_MAX_TOKENS
25 #define CMD_MAX_TOKENS     256
26 #endif
27
28 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
29 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
30 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
31 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
32 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
33 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
34 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
35 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
36 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
37 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
38 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
39
40 #define skip_white_spaces(pos)                  \
41 ({                                              \
42         __typeof__(pos) _p = (pos);             \
43         for ( ; isspace(*_p); _p++)             \
44                 ;                               \
45         _p;                                     \
46 })
47
48 static int
49 parser_read_uint64(uint64_t *value, const char *p)
50 {
51         char *next;
52         uint64_t val;
53
54         p = skip_white_spaces(p);
55         if (!isdigit(*p))
56                 return -EINVAL;
57
58         val = strtoul(p, &next, 0);
59         if (p == next)
60                 return -EINVAL;
61
62         p = next;
63         switch (*p) {
64         case 'T':
65                 val *= 1024ULL;
66                 /* fall through */
67         case 'G':
68                 val *= 1024ULL;
69                 /* fall through */
70         case 'M':
71                 val *= 1024ULL;
72                 /* fall through */
73         case 'k':
74         case 'K':
75                 val *= 1024ULL;
76                 p++;
77                 break;
78         }
79
80         p = skip_white_spaces(p);
81         if (*p != '\0')
82                 return -EINVAL;
83
84         *value = val;
85         return 0;
86 }
87
88 static int
89 parser_read_uint32(uint32_t *value, const char *p)
90 {
91         uint64_t val = 0;
92         int ret = parser_read_uint64(&val, p);
93
94         if (ret < 0)
95                 return ret;
96
97         if (val > UINT32_MAX)
98                 return -ERANGE;
99
100         *value = val;
101         return 0;
102 }
103
104 static int
105 parser_read_uint16(uint16_t *value, const char *p)
106 {
107         uint64_t val = 0;
108         int ret = parser_read_uint64(&val, p);
109
110         if (ret < 0)
111                 return ret;
112
113         if (val > UINT16_MAX)
114                 return -ERANGE;
115
116         *value = val;
117         return 0;
118 }
119
120 #define PARSE_DELIMITER " \f\n\r\t\v"
121
122 static int
123 parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
124 {
125         uint32_t i;
126
127         if ((string == NULL) ||
128                 (tokens == NULL) ||
129                 (*n_tokens < 1))
130                 return -EINVAL;
131
132         for (i = 0; i < *n_tokens; i++) {
133                 tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
134                 if (tokens[i] == NULL)
135                         break;
136         }
137
138         if ((i == *n_tokens) && strtok_r(string, PARSE_DELIMITER, &string))
139                 return -E2BIG;
140
141         *n_tokens = i;
142         return 0;
143 }
144
145 static int
146 is_comment(char *in)
147 {
148         if ((strlen(in) && index("!#%;", in[0])) ||
149                 (strncmp(in, "//", 2) == 0) ||
150                 (strncmp(in, "--", 2) == 0))
151                 return 1;
152
153         return 0;
154 }
155
156 static const char cmd_mempool_help[] =
157 "mempool <mempool_name>\n"
158 "   buffer <buffer_size>\n"
159 "   pool <pool_size>\n"
160 "   cache <cache_size>\n"
161 "   cpu <cpu_id>\n";
162
163 static void
164 cmd_mempool(char **tokens,
165         uint32_t n_tokens,
166         char *out,
167         size_t out_size,
168         void *obj)
169 {
170         struct mempool_params p;
171         char *name;
172         struct mempool *mempool;
173
174         if (n_tokens != 10) {
175                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
176                 return;
177         }
178
179         name = tokens[1];
180
181         if (strcmp(tokens[2], "buffer") != 0) {
182                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
183                 return;
184         }
185
186         if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
187                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
188                 return;
189         }
190
191         if (strcmp(tokens[4], "pool") != 0) {
192                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
193                 return;
194         }
195
196         if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
197                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
198                 return;
199         }
200
201         if (strcmp(tokens[6], "cache") != 0) {
202                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
203                 return;
204         }
205
206         if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
207                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
208                 return;
209         }
210
211         if (strcmp(tokens[8], "cpu") != 0) {
212                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
213                 return;
214         }
215
216         if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
217                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
218                 return;
219         }
220
221         mempool = mempool_create(obj, name, &p);
222         if (mempool == NULL) {
223                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
224                 return;
225         }
226 }
227
228 static const char cmd_link_help[] =
229 "link <link_name>\n"
230 "   dev <device_name> | port <port_id>\n"
231 "   rxq <n_queues> <queue_size> <mempool_name>\n"
232 "   txq <n_queues> <queue_size>\n"
233 "   promiscuous on | off\n"
234 "   [rss <qid_0> ... <qid_n>]\n";
235
236 static void
237 cmd_link(char **tokens,
238         uint32_t n_tokens,
239         char *out,
240         size_t out_size,
241         void *obj)
242 {
243         struct link_params p;
244         struct link_params_rss rss;
245         struct link *link;
246         char *name;
247
248         memset(&p, 0, sizeof(p));
249
250         if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
251                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
252                 return;
253         }
254         name = tokens[1];
255
256         if (strcmp(tokens[2], "dev") == 0)
257                 p.dev_name = tokens[3];
258         else if (strcmp(tokens[2], "port") == 0) {
259                 p.dev_name = NULL;
260
261                 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
262                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
263                         return;
264                 }
265         } else {
266                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
267                 return;
268         }
269
270         if (strcmp(tokens[4], "rxq") != 0) {
271                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
272                 return;
273         }
274
275         if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
276                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
277                 return;
278         }
279         if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
280                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
281                 return;
282         }
283
284         p.rx.mempool_name = tokens[7];
285
286         if (strcmp(tokens[8], "txq") != 0) {
287                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
288                 return;
289         }
290
291         if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
292                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
293                 return;
294         }
295
296         if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
297                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
298                 return;
299         }
300
301         if (strcmp(tokens[11], "promiscuous") != 0) {
302                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
303                 return;
304         }
305
306         if (strcmp(tokens[12], "on") == 0)
307                 p.promiscuous = 1;
308         else if (strcmp(tokens[12], "off") == 0)
309                 p.promiscuous = 0;
310         else {
311                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
312                 return;
313         }
314
315         /* RSS */
316         p.rx.rss = NULL;
317         if (n_tokens > 13) {
318                 uint32_t queue_id, i;
319
320                 if (strcmp(tokens[13], "rss") != 0) {
321                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
322                         return;
323                 }
324
325                 p.rx.rss = &rss;
326
327                 rss.n_queues = 0;
328                 for (i = 14; i < n_tokens; i++) {
329                         if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
330                                 snprintf(out, out_size, MSG_ARG_INVALID,
331                                         "queue_id");
332                                 return;
333                         }
334
335                         rss.queue_id[rss.n_queues] = queue_id;
336                         rss.n_queues++;
337                 }
338         }
339
340         link = link_create(obj, name, &p);
341         if (link == NULL) {
342                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
343                 return;
344         }
345 }
346
347 /* Print the link stats and info */
348 static void
349 print_link_info(struct link *link, char *out, size_t out_size)
350 {
351         struct rte_eth_stats stats;
352         struct rte_ether_addr mac_addr;
353         struct rte_eth_link eth_link;
354         uint16_t mtu;
355         int ret;
356
357         memset(&stats, 0, sizeof(stats));
358         rte_eth_stats_get(link->port_id, &stats);
359
360         ret = rte_eth_macaddr_get(link->port_id, &mac_addr);
361         if (ret != 0) {
362                 snprintf(out, out_size, "\n%s: MAC address get failed: %s",
363                          link->name, rte_strerror(-ret));
364                 return;
365         }
366
367         ret = rte_eth_link_get(link->port_id, &eth_link);
368         if (ret < 0) {
369                 snprintf(out, out_size, "\n%s: link get failed: %s",
370                          link->name, rte_strerror(-ret));
371                 return;
372         }
373
374         rte_eth_dev_get_mtu(link->port_id, &mtu);
375
376         snprintf(out, out_size,
377                 "\n"
378                 "%s: flags=<%s> mtu %u\n"
379                 "\tether " RTE_ETHER_ADDR_PRT_FMT " rxqueues %u txqueues %u\n"
380                 "\tport# %u  speed %s\n"
381                 "\tRX packets %" PRIu64"  bytes %" PRIu64"\n"
382                 "\tRX errors %" PRIu64"  missed %" PRIu64"  no-mbuf %" PRIu64"\n"
383                 "\tTX packets %" PRIu64"  bytes %" PRIu64"\n"
384                 "\tTX errors %" PRIu64"\n",
385                 link->name,
386                 eth_link.link_status == 0 ? "DOWN" : "UP",
387                 mtu,
388                 RTE_ETHER_ADDR_BYTES(&mac_addr),
389                 link->n_rxq,
390                 link->n_txq,
391                 link->port_id,
392                 rte_eth_link_speed_to_str(eth_link.link_speed),
393                 stats.ipackets,
394                 stats.ibytes,
395                 stats.ierrors,
396                 stats.imissed,
397                 stats.rx_nombuf,
398                 stats.opackets,
399                 stats.obytes,
400                 stats.oerrors);
401 }
402
403 /*
404  * link show [<link_name>]
405  */
406 static void
407 cmd_link_show(char **tokens,
408               uint32_t n_tokens,
409               char *out,
410               size_t out_size,
411               void *obj)
412 {
413         struct link *link;
414         char *link_name;
415
416         if (n_tokens != 2 && n_tokens != 3) {
417                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
418                 return;
419         }
420
421         if (n_tokens == 2) {
422                 link = link_next(obj, NULL);
423
424                 while (link != NULL) {
425                         out_size = out_size - strlen(out);
426                         out = &out[strlen(out)];
427
428                         print_link_info(link, out, out_size);
429                         link = link_next(obj, link);
430                 }
431         } else {
432                 out_size = out_size - strlen(out);
433                 out = &out[strlen(out)];
434
435                 link_name = tokens[2];
436                 link = link_find(obj, link_name);
437
438                 if (link == NULL) {
439                         snprintf(out, out_size, MSG_ARG_INVALID,
440                                         "Link does not exist");
441                         return;
442                 }
443                 print_link_info(link, out, out_size);
444         }
445 }
446
447 static const char cmd_ring_help[] =
448 "ring <ring_name> size <size> numa <numa_node>\n";
449
450 static void
451 cmd_ring(char **tokens,
452         uint32_t n_tokens,
453         char *out,
454         size_t out_size,
455         void *obj)
456 {
457         struct ring_params p;
458         char *name;
459         struct ring *ring;
460
461         if (n_tokens != 6) {
462                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
463                 return;
464         }
465
466         name = tokens[1];
467
468         if (strcmp(tokens[2], "size") != 0) {
469                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
470                 return;
471         }
472
473         if (parser_read_uint32(&p.size, tokens[3]) != 0) {
474                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
475                 return;
476         }
477
478         if (strcmp(tokens[4], "numa") != 0) {
479                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa");
480                 return;
481         }
482
483         if (parser_read_uint32(&p.numa_node, tokens[5]) != 0) {
484                 snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
485                 return;
486         }
487
488         ring = ring_create(obj, name, &p);
489         if (!ring) {
490                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
491                 return;
492         }
493 }
494
495 static const char cmd_tap_help[] =
496 "tap <tap_name>\n";
497
498 static void
499 cmd_tap(char **tokens,
500         uint32_t n_tokens,
501         char *out,
502         size_t out_size,
503         void *obj)
504 {
505         struct tap *tap;
506         char *name;
507
508         if (n_tokens < 2) {
509                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
510                 return;
511         }
512         name = tokens[1];
513
514         tap = tap_create(obj, name);
515         if (tap == NULL) {
516                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
517                 return;
518         }
519 }
520
521 static const char cmd_pipeline_create_help[] =
522 "pipeline <pipeline_name> create <numa_node>\n";
523
524 static void
525 cmd_pipeline_create(char **tokens,
526         uint32_t n_tokens,
527         char *out,
528         size_t out_size,
529         void *obj)
530 {
531         struct pipeline *p;
532         char *name;
533         uint32_t numa_node;
534
535         if (n_tokens != 4) {
536                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
537                 return;
538         }
539
540         name = tokens[1];
541
542         if (parser_read_uint32(&numa_node, tokens[3]) != 0) {
543                 snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
544                 return;
545         }
546
547         p = pipeline_create(obj, name, (int)numa_node);
548         if (!p) {
549                 snprintf(out, out_size, "pipeline create error.");
550                 return;
551         }
552 }
553
554 static const char cmd_pipeline_port_in_help[] =
555 "pipeline <pipeline_name> port in <port_id>\n"
556 "   link <link_name> rxq <queue_id> bsz <burst_size>\n"
557 "   ring <ring_name> bsz <burst_size>\n"
558 "   | source <mempool_name> <file_name> loop <n_loops>\n"
559 "   | tap <tap_name> mempool <mempool_name> mtu <mtu> bsz <burst_size>\n";
560
561 static void
562 cmd_pipeline_port_in(char **tokens,
563         uint32_t n_tokens,
564         char *out,
565         size_t out_size,
566         void *obj)
567 {
568         struct pipeline *p;
569         int status;
570         uint32_t port_id = 0, t0;
571
572         if (n_tokens < 6) {
573                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
574                 return;
575         }
576
577         p = pipeline_find(obj, tokens[1]);
578         if (!p || p->ctl) {
579                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
580                 return;
581         }
582
583         if (strcmp(tokens[2], "port") != 0) {
584                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
585                 return;
586         }
587
588         if (strcmp(tokens[3], "in") != 0) {
589                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
590                 return;
591         }
592
593         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
594                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
595                 return;
596         }
597
598         t0 = 5;
599
600         if (strcmp(tokens[t0], "link") == 0) {
601                 struct rte_swx_port_ethdev_reader_params params;
602                 struct link *link;
603
604                 if (n_tokens < t0 + 6) {
605                         snprintf(out, out_size, MSG_ARG_MISMATCH,
606                                 "pipeline port in link");
607                         return;
608                 }
609
610                 link = link_find(obj, tokens[t0 + 1]);
611                 if (!link) {
612                         snprintf(out, out_size, MSG_ARG_INVALID,
613                                 "link_name");
614                         return;
615                 }
616                 params.dev_name = link->dev_name;
617
618                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
619                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
620                         return;
621                 }
622
623                 if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
624                         snprintf(out, out_size, MSG_ARG_INVALID,
625                                 "queue_id");
626                         return;
627                 }
628
629                 if (strcmp(tokens[t0 + 4], "bsz") != 0) {
630                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
631                         return;
632                 }
633
634                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
635                         snprintf(out, out_size, MSG_ARG_INVALID,
636                                 "burst_size");
637                         return;
638                 }
639
640                 t0 += 6;
641
642                 status = rte_swx_pipeline_port_in_config(p->p,
643                         port_id,
644                         "ethdev",
645                         &params);
646         } else if (strcmp(tokens[t0], "ring") == 0) {
647                 struct rte_swx_port_ring_reader_params params;
648                 struct ring *ring;
649
650                 if (n_tokens < t0 + 4) {
651                         snprintf(out, out_size, MSG_ARG_MISMATCH,
652                                 "pipeline port in ring");
653                         return;
654                 }
655
656                 ring = ring_find(obj, tokens[t0 + 1]);
657                 if (!ring) {
658                         snprintf(out, out_size, MSG_ARG_INVALID,
659                                 "ring_name");
660                         return;
661                 }
662                 params.name = ring->name;
663
664                 if (strcmp(tokens[t0 + 2], "bsz") != 0) {
665                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
666                         return;
667                 }
668
669                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
670                         snprintf(out, out_size, MSG_ARG_INVALID,
671                                 "burst_size");
672                         return;
673                 }
674
675                 t0 += 4;
676
677                 status = rte_swx_pipeline_port_in_config(p->p,
678                         port_id,
679                         "ring",
680                         &params);
681         } else if (strcmp(tokens[t0], "source") == 0) {
682                 struct rte_swx_port_source_params params;
683                 struct mempool *mp;
684
685                 if (n_tokens < t0 + 5) {
686                         snprintf(out, out_size, MSG_ARG_MISMATCH,
687                                 "pipeline port in source");
688                         return;
689                 }
690
691                 mp = mempool_find(obj, tokens[t0 + 1]);
692                 if (!mp) {
693                         snprintf(out, out_size, MSG_ARG_INVALID,
694                                 "mempool_name");
695                         return;
696                 }
697                 params.pool = mp->m;
698
699                 params.file_name = tokens[t0 + 2];
700
701                 if (strcmp(tokens[t0 + 3], "loop") != 0) {
702                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "loop");
703                         return;
704                 }
705
706                 if (parser_read_uint64(&params.n_loops, tokens[t0 + 4])) {
707                         snprintf(out, out_size, MSG_ARG_INVALID,
708                                 "n_loops");
709                         return;
710                 }
711
712                 t0 += 5;
713
714                 status = rte_swx_pipeline_port_in_config(p->p,
715                         port_id,
716                         "source",
717                         &params);
718         } else if (strcmp(tokens[t0], "tap") == 0) {
719                 struct rte_swx_port_fd_reader_params params;
720                 struct tap *tap;
721                 struct mempool *mp;
722
723                 if (n_tokens < t0 + 8) {
724                         snprintf(out, out_size, MSG_ARG_MISMATCH,
725                                 "pipeline port in tap");
726                         return;
727                 }
728
729                 tap = tap_find(obj, tokens[t0 + 1]);
730                 if (!tap) {
731                         snprintf(out, out_size, MSG_ARG_INVALID,
732                                 "tap_name");
733                         return;
734                 }
735                 params.fd = tap->fd;
736
737                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
738                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
739                                 "mempool");
740                         return;
741                 }
742
743                 mp = mempool_find(obj, tokens[t0 + 3]);
744                 if (!mp) {
745                         snprintf(out, out_size, MSG_ARG_INVALID,
746                                 "mempool_name");
747                         return;
748                 }
749                 params.mempool = mp->m;
750
751                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
752                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
753                                 "mtu");
754                         return;
755                 }
756
757                 if (parser_read_uint32(&params.mtu, tokens[t0 + 5]) != 0) {
758                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
759                         return;
760                 }
761
762                 if (strcmp(tokens[t0 + 6], "bsz") != 0) {
763                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
764                         return;
765                 }
766
767                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 7])) {
768                         snprintf(out, out_size, MSG_ARG_INVALID,
769                                 "burst_size");
770                         return;
771                 }
772
773                 t0 += 8;
774
775                 status = rte_swx_pipeline_port_in_config(p->p,
776                         port_id,
777                         "fd",
778                         &params);
779
780         } else {
781                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
782                 return;
783         }
784
785         if (status) {
786                 snprintf(out, out_size, "port in error.");
787                 return;
788         }
789
790         if (n_tokens != t0) {
791                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
792                 return;
793         }
794 }
795
796 static const char cmd_pipeline_port_out_help[] =
797 "pipeline <pipeline_name> port out <port_id>\n"
798 "   link <link_name> txq <txq_id> bsz <burst_size>\n"
799 "   ring <ring_name> bsz <burst_size>\n"
800 "   | sink <file_name> | none\n"
801 "   | tap <tap_name> bsz <burst_size>\n";
802
803 static void
804 cmd_pipeline_port_out(char **tokens,
805         uint32_t n_tokens,
806         char *out,
807         size_t out_size,
808         void *obj)
809 {
810         struct pipeline *p;
811         int status;
812         uint32_t port_id = 0, t0;
813
814         if (n_tokens < 6) {
815                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
816                 return;
817         }
818
819         p = pipeline_find(obj, tokens[1]);
820         if (!p || p->ctl) {
821                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
822                 return;
823         }
824
825         if (strcmp(tokens[2], "port") != 0) {
826                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
827                 return;
828         }
829
830         if (strcmp(tokens[3], "out") != 0) {
831                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
832                 return;
833         }
834
835         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
836                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
837                 return;
838         }
839
840         t0 = 5;
841
842         if (strcmp(tokens[t0], "link") == 0) {
843                 struct rte_swx_port_ethdev_writer_params params;
844                 struct link *link;
845
846                 if (n_tokens < t0 + 6) {
847                         snprintf(out, out_size, MSG_ARG_MISMATCH,
848                                 "pipeline port out link");
849                         return;
850                 }
851
852                 link = link_find(obj, tokens[t0 + 1]);
853                 if (!link) {
854                         snprintf(out, out_size, MSG_ARG_INVALID,
855                                 "link_name");
856                         return;
857                 }
858                 params.dev_name = link->dev_name;
859
860                 if (strcmp(tokens[t0 + 2], "txq") != 0) {
861                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
862                         return;
863                 }
864
865                 if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
866                         snprintf(out, out_size, MSG_ARG_INVALID,
867                                 "queue_id");
868                         return;
869                 }
870
871                 if (strcmp(tokens[t0 + 4], "bsz") != 0) {
872                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
873                         return;
874                 }
875
876                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
877                         snprintf(out, out_size, MSG_ARG_INVALID,
878                                 "burst_size");
879                         return;
880                 }
881
882                 t0 += 6;
883
884                 status = rte_swx_pipeline_port_out_config(p->p,
885                         port_id,
886                         "ethdev",
887                         &params);
888         } else if (strcmp(tokens[t0], "ring") == 0) {
889                 struct rte_swx_port_ring_writer_params params;
890                 struct ring *ring;
891
892                 if (n_tokens < t0 + 4) {
893                         snprintf(out, out_size, MSG_ARG_MISMATCH,
894                                 "pipeline port out link");
895                         return;
896                 }
897
898                 ring = ring_find(obj, tokens[t0 + 1]);
899                 if (!ring) {
900                         snprintf(out, out_size, MSG_ARG_INVALID,
901                                 "ring_name");
902                         return;
903                 }
904                 params.name = ring->name;
905
906                 if (strcmp(tokens[t0 + 2], "bsz") != 0) {
907                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
908                         return;
909                 }
910
911                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
912                         snprintf(out, out_size, MSG_ARG_INVALID,
913                                 "burst_size");
914                         return;
915                 }
916
917                 t0 += 4;
918
919                 status = rte_swx_pipeline_port_out_config(p->p,
920                         port_id,
921                         "ring",
922                         &params);
923         } else if (strcmp(tokens[t0], "sink") == 0) {
924                 struct rte_swx_port_sink_params params;
925
926                 params.file_name = strcmp(tokens[t0 + 1], "none") ?
927                         tokens[t0 + 1] : NULL;
928
929                 t0 += 2;
930
931                 status = rte_swx_pipeline_port_out_config(p->p,
932                         port_id,
933                         "sink",
934                         &params);
935         } else if (strcmp(tokens[t0], "tap") == 0) {
936                 struct rte_swx_port_fd_writer_params params;
937                 struct tap *tap;
938
939                 if (n_tokens < t0 + 4) {
940                         snprintf(out, out_size, MSG_ARG_MISMATCH,
941                                 "pipeline port out tap");
942                         return;
943                 }
944
945                 tap = tap_find(obj, tokens[t0 + 1]);
946                 if (!tap) {
947                         snprintf(out, out_size, MSG_ARG_INVALID,
948                                 "tap_name");
949                         return;
950                 }
951                 params.fd = tap->fd;
952
953                 if (strcmp(tokens[t0 + 2], "bsz") != 0) {
954                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
955                         return;
956                 }
957
958                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
959                         snprintf(out, out_size, MSG_ARG_INVALID,
960                                 "burst_size");
961                         return;
962                 }
963
964                 t0 += 4;
965
966                 status = rte_swx_pipeline_port_out_config(p->p,
967                         port_id,
968                         "fd",
969                         &params);
970         } else {
971                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
972                 return;
973         }
974
975         if (status) {
976                 snprintf(out, out_size, "port out error.");
977                 return;
978         }
979
980         if (n_tokens != t0) {
981                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
982                 return;
983         }
984 }
985
986 static const char cmd_pipeline_build_help[] =
987 "pipeline <pipeline_name> build <spec_file>\n";
988
989 static void
990 cmd_pipeline_build(char **tokens,
991         uint32_t n_tokens,
992         char *out,
993         size_t out_size,
994         void *obj)
995 {
996         struct pipeline *p = NULL;
997         FILE *spec = NULL;
998         uint32_t err_line;
999         const char *err_msg;
1000         int status;
1001
1002         if (n_tokens != 4) {
1003                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1004                 return;
1005         }
1006
1007         p = pipeline_find(obj, tokens[1]);
1008         if (!p || p->ctl) {
1009                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1010                 return;
1011         }
1012
1013         spec = fopen(tokens[3], "r");
1014         if (!spec) {
1015                 snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
1016                 return;
1017         }
1018
1019         status = rte_swx_pipeline_build_from_spec(p->p,
1020                 spec,
1021                 &err_line,
1022                 &err_msg);
1023         fclose(spec);
1024         if (status) {
1025                 snprintf(out, out_size, "Error %d at line %u: %s\n.",
1026                         status, err_line, err_msg);
1027                 return;
1028         }
1029
1030         p->ctl = rte_swx_ctl_pipeline_create(p->p);
1031         if (!p->ctl) {
1032                 snprintf(out, out_size, "Pipeline control create failed.");
1033                 rte_swx_pipeline_free(p->p);
1034                 return;
1035         }
1036 }
1037
1038 static void
1039 table_entry_free(struct rte_swx_table_entry *entry)
1040 {
1041         if (!entry)
1042                 return;
1043
1044         free(entry->key);
1045         free(entry->key_mask);
1046         free(entry->action_data);
1047         free(entry);
1048 }
1049
1050 #ifndef MAX_LINE_SIZE
1051 #define MAX_LINE_SIZE 2048
1052 #endif
1053
1054 static int
1055 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p,
1056                            const char *table_name,
1057                            FILE *file,
1058                            uint32_t *file_line_number)
1059 {
1060         char *line = NULL;
1061         uint32_t line_id = 0;
1062         int status = 0;
1063
1064         /* Buffer allocation. */
1065         line = malloc(MAX_LINE_SIZE);
1066         if (!line)
1067                 return -ENOMEM;
1068
1069         /* File read. */
1070         for (line_id = 1; ; line_id++) {
1071                 struct rte_swx_table_entry *entry;
1072                 int is_blank_or_comment;
1073
1074                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1075                         break;
1076
1077                 entry = rte_swx_ctl_pipeline_table_entry_read(p,
1078                                                               table_name,
1079                                                               line,
1080                                                               &is_blank_or_comment);
1081                 if (!entry) {
1082                         if (is_blank_or_comment)
1083                                 continue;
1084
1085                         status = -EINVAL;
1086                         goto error;
1087                 }
1088
1089                 status = rte_swx_ctl_pipeline_table_entry_add(p,
1090                                                               table_name,
1091                                                               entry);
1092                 table_entry_free(entry);
1093                 if (status)
1094                         goto error;
1095         }
1096
1097 error:
1098         free(line);
1099         *file_line_number = line_id;
1100         return status;
1101 }
1102
1103 static const char cmd_pipeline_table_add_help[] =
1104 "pipeline <pipeline_name> table <table_name> add <file_name>\n";
1105
1106 static void
1107 cmd_pipeline_table_add(char **tokens,
1108                        uint32_t n_tokens,
1109                        char *out,
1110                        size_t out_size,
1111                        void *obj)
1112 {
1113         struct pipeline *p;
1114         char *pipeline_name, *table_name, *file_name;
1115         FILE *file = NULL;
1116         uint32_t file_line_number = 0;
1117         int status;
1118
1119         if (n_tokens != 6) {
1120                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1121                 return;
1122         }
1123
1124         pipeline_name = tokens[1];
1125         p = pipeline_find(obj, pipeline_name);
1126         if (!p || !p->ctl) {
1127                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1128                 return;
1129         }
1130
1131         table_name = tokens[3];
1132
1133         file_name = tokens[5];
1134         file = fopen(file_name, "r");
1135         if (!file) {
1136                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1137                 return;
1138         }
1139
1140         status = pipeline_table_entries_add(p->ctl,
1141                                             table_name,
1142                                             file,
1143                                             &file_line_number);
1144         if (status)
1145                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1146                          file_name,
1147                          file_line_number);
1148
1149         fclose(file);
1150 }
1151
1152 static int
1153 pipeline_table_entries_delete(struct rte_swx_ctl_pipeline *p,
1154                               const char *table_name,
1155                               FILE *file,
1156                               uint32_t *file_line_number)
1157 {
1158         char *line = NULL;
1159         uint32_t line_id = 0;
1160         int status = 0;
1161
1162         /* Buffer allocation. */
1163         line = malloc(MAX_LINE_SIZE);
1164         if (!line)
1165                 return -ENOMEM;
1166
1167         /* File read. */
1168         for (line_id = 1; ; line_id++) {
1169                 struct rte_swx_table_entry *entry;
1170                 int is_blank_or_comment;
1171
1172                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1173                         break;
1174
1175                 entry = rte_swx_ctl_pipeline_table_entry_read(p,
1176                                                               table_name,
1177                                                               line,
1178                                                               &is_blank_or_comment);
1179                 if (!entry) {
1180                         if (is_blank_or_comment)
1181                                 continue;
1182
1183                         status = -EINVAL;
1184                         goto error;
1185                 }
1186
1187                 status = rte_swx_ctl_pipeline_table_entry_delete(p,
1188                                                                  table_name,
1189                                                                  entry);
1190                 table_entry_free(entry);
1191                 if (status)
1192                         goto error;
1193         }
1194
1195 error:
1196         *file_line_number = line_id;
1197         free(line);
1198         return status;
1199 }
1200
1201 static const char cmd_pipeline_table_delete_help[] =
1202 "pipeline <pipeline_name> table <table_name> delete <file_name>\n";
1203
1204 static void
1205 cmd_pipeline_table_delete(char **tokens,
1206                           uint32_t n_tokens,
1207                           char *out,
1208                           size_t out_size,
1209                           void *obj)
1210 {
1211         struct pipeline *p;
1212         char *pipeline_name, *table_name, *file_name;
1213         FILE *file = NULL;
1214         uint32_t file_line_number = 0;
1215         int status;
1216
1217         if (n_tokens != 6) {
1218                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1219                 return;
1220         }
1221
1222         pipeline_name = tokens[1];
1223         p = pipeline_find(obj, pipeline_name);
1224         if (!p || !p->ctl) {
1225                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1226                 return;
1227         }
1228
1229         table_name = tokens[3];
1230
1231         file_name = tokens[5];
1232         file = fopen(file_name, "r");
1233         if (!file) {
1234                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1235                 return;
1236         }
1237
1238         status = pipeline_table_entries_delete(p->ctl,
1239                                                table_name,
1240                                                file,
1241                                                &file_line_number);
1242         if (status)
1243                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1244                          file_name,
1245                          file_line_number);
1246
1247         fclose(file);
1248 }
1249
1250 static int
1251 pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *p,
1252                                  const char *table_name,
1253                                  FILE *file,
1254                                  uint32_t *file_line_number)
1255 {
1256         char *line = NULL;
1257         uint32_t line_id = 0;
1258         int status = 0;
1259
1260         /* Buffer allocation. */
1261         line = malloc(MAX_LINE_SIZE);
1262         if (!line)
1263                 return -ENOMEM;
1264
1265         /* File read. */
1266         for (line_id = 1; ; line_id++) {
1267                 struct rte_swx_table_entry *entry;
1268                 int is_blank_or_comment;
1269
1270                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1271                         break;
1272
1273                 entry = rte_swx_ctl_pipeline_table_entry_read(p,
1274                                                               table_name,
1275                                                               line,
1276                                                               &is_blank_or_comment);
1277                 if (!entry) {
1278                         if (is_blank_or_comment)
1279                                 continue;
1280
1281                         status = -EINVAL;
1282                         goto error;
1283                 }
1284
1285                 status = rte_swx_ctl_pipeline_table_default_entry_add(p,
1286                                                                       table_name,
1287                                                                       entry);
1288                 table_entry_free(entry);
1289                 if (status)
1290                         goto error;
1291         }
1292
1293 error:
1294         *file_line_number = line_id;
1295         free(line);
1296         return status;
1297 }
1298
1299 static const char cmd_pipeline_table_default_help[] =
1300 "pipeline <pipeline_name> table <table_name> default <file_name>\n";
1301
1302 static void
1303 cmd_pipeline_table_default(char **tokens,
1304                            uint32_t n_tokens,
1305                            char *out,
1306                            size_t out_size,
1307                            void *obj)
1308 {
1309         struct pipeline *p;
1310         char *pipeline_name, *table_name, *file_name;
1311         FILE *file = NULL;
1312         uint32_t file_line_number = 0;
1313         int status;
1314
1315         if (n_tokens != 6) {
1316                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1317                 return;
1318         }
1319
1320         pipeline_name = tokens[1];
1321         p = pipeline_find(obj, pipeline_name);
1322         if (!p || !p->ctl) {
1323                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1324                 return;
1325         }
1326
1327         table_name = tokens[3];
1328
1329         file_name = tokens[5];
1330         file = fopen(file_name, "r");
1331         if (!file) {
1332                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1333                 return;
1334         }
1335
1336         status = pipeline_table_default_entry_add(p->ctl,
1337                                                   table_name,
1338                                                   file,
1339                                                   &file_line_number);
1340         if (status)
1341                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1342                          file_name,
1343                          file_line_number);
1344
1345         fclose(file);
1346 }
1347
1348 static const char cmd_pipeline_table_show_help[] =
1349 "pipeline <pipeline_name> table <table_name> show [filename]\n";
1350
1351 static void
1352 cmd_pipeline_table_show(char **tokens,
1353         uint32_t n_tokens,
1354         char *out,
1355         size_t out_size,
1356         void *obj)
1357 {
1358         struct pipeline *p;
1359         char *pipeline_name, *table_name;
1360         FILE *file = NULL;
1361         int status;
1362
1363         if (n_tokens != 5 && n_tokens != 6) {
1364                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1365                 return;
1366         }
1367
1368         pipeline_name = tokens[1];
1369         p = pipeline_find(obj, pipeline_name);
1370         if (!p || !p->ctl) {
1371                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1372                 return;
1373         }
1374
1375         table_name = tokens[3];
1376         file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout;
1377         if (!file) {
1378                 snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]);
1379                 return;
1380         }
1381
1382         status = rte_swx_ctl_pipeline_table_fprintf(file, p->ctl, table_name);
1383         if (status)
1384                 snprintf(out, out_size, MSG_ARG_INVALID, "table_name");
1385
1386         if (file)
1387                 fclose(file);
1388 }
1389
1390 static const char cmd_pipeline_selector_group_add_help[] =
1391 "pipeline <pipeline_name> selector <selector_name> group add\n";
1392
1393 static void
1394 cmd_pipeline_selector_group_add(char **tokens,
1395         uint32_t n_tokens,
1396         char *out,
1397         size_t out_size,
1398         void *obj)
1399 {
1400         struct pipeline *p;
1401         char *pipeline_name, *selector_name;
1402         uint32_t group_id;
1403         int status;
1404
1405         if (n_tokens != 6) {
1406                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1407                 return;
1408         }
1409
1410         pipeline_name = tokens[1];
1411         p = pipeline_find(obj, pipeline_name);
1412         if (!p || !p->ctl) {
1413                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1414                 return;
1415         }
1416
1417         if (strcmp(tokens[2], "selector") != 0) {
1418                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1419                 return;
1420         }
1421
1422         selector_name = tokens[3];
1423
1424         if (strcmp(tokens[4], "group") ||
1425                 strcmp(tokens[5], "add")) {
1426                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group add");
1427                 return;
1428         }
1429
1430         status = rte_swx_ctl_pipeline_selector_group_add(p->ctl,
1431                 selector_name,
1432                 &group_id);
1433         if (status)
1434                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1435         else
1436                 snprintf(out, out_size, "Group ID: %u\n", group_id);
1437 }
1438
1439 static const char cmd_pipeline_selector_group_delete_help[] =
1440 "pipeline <pipeline_name> selector <selector_name> group delete <group_id>\n";
1441
1442 static void
1443 cmd_pipeline_selector_group_delete(char **tokens,
1444         uint32_t n_tokens,
1445         char *out,
1446         size_t out_size,
1447         void *obj)
1448 {
1449         struct pipeline *p;
1450         char *pipeline_name, *selector_name;
1451         uint32_t group_id;
1452         int status;
1453
1454         if (n_tokens != 7) {
1455                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1456                 return;
1457         }
1458
1459         pipeline_name = tokens[1];
1460         p = pipeline_find(obj, pipeline_name);
1461         if (!p || !p->ctl) {
1462                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1463                 return;
1464         }
1465
1466         if (strcmp(tokens[2], "selector") != 0) {
1467                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1468                 return;
1469         }
1470
1471         selector_name = tokens[3];
1472
1473         if (strcmp(tokens[4], "group") ||
1474                 strcmp(tokens[5], "delete")) {
1475                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group delete");
1476                 return;
1477         }
1478
1479         if (parser_read_uint32(&group_id, tokens[6]) != 0) {
1480                 snprintf(out, out_size, MSG_ARG_INVALID, "group_id");
1481                 return;
1482         }
1483
1484         status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl,
1485                 selector_name,
1486                 group_id);
1487         if (status)
1488                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1489 }
1490
1491 #define GROUP_MEMBER_INFO_TOKENS_MAX 6
1492
1493 static int
1494 token_is_comment(const char *token)
1495 {
1496         if ((token[0] == '#') ||
1497             (token[0] == ';') ||
1498             ((token[0] == '/') && (token[1] == '/')))
1499                 return 1; /* TRUE. */
1500
1501         return 0; /* FALSE. */
1502 }
1503
1504 static int
1505 pipeline_selector_group_member_read(const char *string,
1506                                       uint32_t *group_id,
1507                                       uint32_t *member_id,
1508                                       uint32_t *weight,
1509                                       int *is_blank_or_comment)
1510 {
1511         char *token_array[GROUP_MEMBER_INFO_TOKENS_MAX], **tokens;
1512         char *s0 = NULL, *s;
1513         uint32_t n_tokens = 0, group_id_val = 0, member_id_val = 0, weight_val = 0;
1514         int blank_or_comment = 0;
1515
1516         /* Check input arguments. */
1517         if (!string || !string[0])
1518                 goto error;
1519
1520         /* Memory allocation. */
1521         s0 = strdup(string);
1522         if (!s0)
1523                 goto error;
1524
1525         /* Parse the string into tokens. */
1526         for (s = s0; ; ) {
1527                 char *token;
1528
1529                 token = strtok_r(s, " \f\n\r\t\v", &s);
1530                 if (!token || token_is_comment(token))
1531                         break;
1532
1533                 if (n_tokens >= GROUP_MEMBER_INFO_TOKENS_MAX)
1534                         goto error;
1535
1536                 token_array[n_tokens] = token;
1537                 n_tokens++;
1538         }
1539
1540         if (!n_tokens) {
1541                 blank_or_comment = 1;
1542                 goto error;
1543         }
1544
1545         tokens = token_array;
1546
1547         if (n_tokens < 4 ||
1548                 strcmp(tokens[0], "group") ||
1549                 strcmp(tokens[2], "member"))
1550                 goto error;
1551
1552         /*
1553          * Group ID.
1554          */
1555         if (parser_read_uint32(&group_id_val, tokens[1]) != 0)
1556                 goto error;
1557         *group_id = group_id_val;
1558
1559         /*
1560          * Member ID.
1561          */
1562         if (parser_read_uint32(&member_id_val, tokens[3]) != 0)
1563                 goto error;
1564         *member_id = member_id_val;
1565
1566         tokens += 4;
1567         n_tokens -= 4;
1568
1569         /*
1570          * Weight.
1571          */
1572         if (n_tokens && !strcmp(tokens[0], "weight")) {
1573                 if (n_tokens < 2)
1574                         goto error;
1575
1576                 if (parser_read_uint32(&weight_val, tokens[1]) != 0)
1577                         goto error;
1578                 *weight = weight_val;
1579
1580                 tokens += 2;
1581                 n_tokens -= 2;
1582         }
1583
1584         if (n_tokens)
1585                 goto error;
1586
1587         free(s0);
1588         return 0;
1589
1590 error:
1591         free(s0);
1592         if (is_blank_or_comment)
1593                 *is_blank_or_comment = blank_or_comment;
1594         return -EINVAL;
1595 }
1596
1597 static int
1598 pipeline_selector_group_members_add(struct rte_swx_ctl_pipeline *p,
1599                            const char *selector_name,
1600                            FILE *file,
1601                            uint32_t *file_line_number)
1602 {
1603         char *line = NULL;
1604         uint32_t line_id = 0;
1605         int status = 0;
1606
1607         /* Buffer allocation. */
1608         line = malloc(MAX_LINE_SIZE);
1609         if (!line)
1610                 return -ENOMEM;
1611
1612         /* File read. */
1613         for (line_id = 1; ; line_id++) {
1614                 uint32_t group_id, member_id, weight;
1615                 int is_blank_or_comment;
1616
1617                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1618                         break;
1619
1620                 status = pipeline_selector_group_member_read(line,
1621                                                               &group_id,
1622                                                               &member_id,
1623                                                               &weight,
1624                                                               &is_blank_or_comment);
1625                 if (status) {
1626                         if (is_blank_or_comment)
1627                                 continue;
1628
1629                         goto error;
1630                 }
1631
1632                 status = rte_swx_ctl_pipeline_selector_group_member_add(p,
1633                         selector_name,
1634                         group_id,
1635                         member_id,
1636                         weight);
1637                 if (status)
1638                         goto error;
1639         }
1640
1641 error:
1642         free(line);
1643         *file_line_number = line_id;
1644         return status;
1645 }
1646
1647 static const char cmd_pipeline_selector_group_member_add_help[] =
1648 "pipeline <pipeline_name> selector <selector_name> group member add <file_name>";
1649
1650 static void
1651 cmd_pipeline_selector_group_member_add(char **tokens,
1652         uint32_t n_tokens,
1653         char *out,
1654         size_t out_size,
1655         void *obj)
1656 {
1657         struct pipeline *p;
1658         char *pipeline_name, *selector_name, *file_name;
1659         FILE *file = NULL;
1660         uint32_t file_line_number = 0;
1661         int status;
1662
1663         if (n_tokens != 8) {
1664                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1665                 return;
1666         }
1667
1668         pipeline_name = tokens[1];
1669         p = pipeline_find(obj, pipeline_name);
1670         if (!p || !p->ctl) {
1671                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1672                 return;
1673         }
1674
1675         if (strcmp(tokens[2], "selector") != 0) {
1676                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1677                 return;
1678         }
1679
1680         selector_name = tokens[3];
1681
1682         if (strcmp(tokens[4], "group") ||
1683                 strcmp(tokens[5], "member") ||
1684                 strcmp(tokens[6], "add")) {
1685                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member add");
1686                 return;
1687         }
1688
1689         file_name = tokens[7];
1690         file = fopen(file_name, "r");
1691         if (!file) {
1692                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1693                 return;
1694         }
1695
1696         status = pipeline_selector_group_members_add(p->ctl,
1697                                             selector_name,
1698                                             file,
1699                                             &file_line_number);
1700         if (status)
1701                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1702                          file_name,
1703                          file_line_number);
1704
1705         fclose(file);
1706 }
1707
1708 static int
1709 pipeline_selector_group_members_delete(struct rte_swx_ctl_pipeline *p,
1710                            const char *selector_name,
1711                            FILE *file,
1712                            uint32_t *file_line_number)
1713 {
1714         char *line = NULL;
1715         uint32_t line_id = 0;
1716         int status = 0;
1717
1718         /* Buffer allocation. */
1719         line = malloc(MAX_LINE_SIZE);
1720         if (!line)
1721                 return -ENOMEM;
1722
1723         /* File read. */
1724         for (line_id = 1; ; line_id++) {
1725                 uint32_t group_id, member_id, weight;
1726                 int is_blank_or_comment;
1727
1728                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1729                         break;
1730
1731                 status = pipeline_selector_group_member_read(line,
1732                                                               &group_id,
1733                                                               &member_id,
1734                                                               &weight,
1735                                                               &is_blank_or_comment);
1736                 if (status) {
1737                         if (is_blank_or_comment)
1738                                 continue;
1739
1740                         goto error;
1741                 }
1742
1743                 status = rte_swx_ctl_pipeline_selector_group_member_delete(p,
1744                         selector_name,
1745                         group_id,
1746                         member_id);
1747                 if (status)
1748                         goto error;
1749         }
1750
1751 error:
1752         free(line);
1753         *file_line_number = line_id;
1754         return status;
1755 }
1756
1757 static const char cmd_pipeline_selector_group_member_delete_help[] =
1758 "pipeline <pipeline_name> selector <selector_name> group member delete <file_name>";
1759
1760 static void
1761 cmd_pipeline_selector_group_member_delete(char **tokens,
1762         uint32_t n_tokens,
1763         char *out,
1764         size_t out_size,
1765         void *obj)
1766 {
1767         struct pipeline *p;
1768         char *pipeline_name, *selector_name, *file_name;
1769         FILE *file = NULL;
1770         uint32_t file_line_number = 0;
1771         int status;
1772
1773         if (n_tokens != 8) {
1774                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1775                 return;
1776         }
1777
1778         pipeline_name = tokens[1];
1779         p = pipeline_find(obj, pipeline_name);
1780         if (!p || !p->ctl) {
1781                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1782                 return;
1783         }
1784
1785         if (strcmp(tokens[2], "selector") != 0) {
1786                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1787                 return;
1788         }
1789
1790         selector_name = tokens[3];
1791
1792         if (strcmp(tokens[4], "group") ||
1793                 strcmp(tokens[5], "member") ||
1794                 strcmp(tokens[6], "delete")) {
1795                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member delete");
1796                 return;
1797         }
1798
1799         file_name = tokens[7];
1800         file = fopen(file_name, "r");
1801         if (!file) {
1802                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1803                 return;
1804         }
1805
1806         status = pipeline_selector_group_members_delete(p->ctl,
1807                                             selector_name,
1808                                             file,
1809                                             &file_line_number);
1810         if (status)
1811                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1812                          file_name,
1813                          file_line_number);
1814
1815         fclose(file);
1816 }
1817
1818 static const char cmd_pipeline_selector_show_help[] =
1819 "pipeline <pipeline_name> selector <selector_name> show [filename]\n";
1820
1821 static void
1822 cmd_pipeline_selector_show(char **tokens,
1823         uint32_t n_tokens,
1824         char *out,
1825         size_t out_size,
1826         void *obj)
1827 {
1828         struct pipeline *p;
1829         char *pipeline_name, *selector_name;
1830         FILE *file = NULL;
1831         int status;
1832
1833         if (n_tokens != 5 && n_tokens != 6) {
1834                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1835                 return;
1836         }
1837
1838         pipeline_name = tokens[1];
1839         p = pipeline_find(obj, pipeline_name);
1840         if (!p || !p->ctl) {
1841                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1842                 return;
1843         }
1844
1845         selector_name = tokens[3];
1846
1847         file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout;
1848         if (!file) {
1849                 snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]);
1850                 return;
1851         }
1852
1853         status = rte_swx_ctl_pipeline_selector_fprintf(file, p->ctl, selector_name);
1854         if (status)
1855                 snprintf(out, out_size, MSG_ARG_INVALID, "selector_name");
1856
1857         if (file)
1858                 fclose(file);
1859 }
1860
1861 static int
1862 pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *p,
1863                                    const char *learner_name,
1864                                    FILE *file,
1865                                    uint32_t *file_line_number)
1866 {
1867         char *line = NULL;
1868         uint32_t line_id = 0;
1869         int status = 0;
1870
1871         /* Buffer allocation. */
1872         line = malloc(MAX_LINE_SIZE);
1873         if (!line)
1874                 return -ENOMEM;
1875
1876         /* File read. */
1877         for (line_id = 1; ; line_id++) {
1878                 struct rte_swx_table_entry *entry;
1879                 int is_blank_or_comment;
1880
1881                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1882                         break;
1883
1884                 entry = rte_swx_ctl_pipeline_learner_default_entry_read(p,
1885                                                                         learner_name,
1886                                                                         line,
1887                                                                         &is_blank_or_comment);
1888                 if (!entry) {
1889                         if (is_blank_or_comment)
1890                                 continue;
1891
1892                         status = -EINVAL;
1893                         goto error;
1894                 }
1895
1896                 status = rte_swx_ctl_pipeline_learner_default_entry_add(p,
1897                                                                         learner_name,
1898                                                                         entry);
1899                 table_entry_free(entry);
1900                 if (status)
1901                         goto error;
1902         }
1903
1904 error:
1905         *file_line_number = line_id;
1906         free(line);
1907         return status;
1908 }
1909
1910 static const char cmd_pipeline_learner_default_help[] =
1911 "pipeline <pipeline_name> learner <learner_name> default <file_name>\n";
1912
1913 static void
1914 cmd_pipeline_learner_default(char **tokens,
1915                              uint32_t n_tokens,
1916                              char *out,
1917                              size_t out_size,
1918                              void *obj)
1919 {
1920         struct pipeline *p;
1921         char *pipeline_name, *learner_name, *file_name;
1922         FILE *file = NULL;
1923         uint32_t file_line_number = 0;
1924         int status;
1925
1926         if (n_tokens != 6) {
1927                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1928                 return;
1929         }
1930
1931         pipeline_name = tokens[1];
1932         p = pipeline_find(obj, pipeline_name);
1933         if (!p || !p->ctl) {
1934                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1935                 return;
1936         }
1937
1938         learner_name = tokens[3];
1939
1940         file_name = tokens[5];
1941         file = fopen(file_name, "r");
1942         if (!file) {
1943                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1944                 return;
1945         }
1946
1947         status = pipeline_learner_default_entry_add(p->ctl,
1948                                                     learner_name,
1949                                                     file,
1950                                                     &file_line_number);
1951         if (status)
1952                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1953                          file_name,
1954                          file_line_number);
1955
1956         fclose(file);
1957 }
1958
1959 static const char cmd_pipeline_commit_help[] =
1960 "pipeline <pipeline_name> commit\n";
1961
1962 static void
1963 cmd_pipeline_commit(char **tokens,
1964         uint32_t n_tokens,
1965         char *out,
1966         size_t out_size,
1967         void *obj)
1968 {
1969         struct pipeline *p;
1970         char *pipeline_name;
1971         int status;
1972
1973         if (n_tokens != 3) {
1974                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1975                 return;
1976         }
1977
1978         pipeline_name = tokens[1];
1979         p = pipeline_find(obj, pipeline_name);
1980         if (!p || !p->ctl) {
1981                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1982                 return;
1983         }
1984
1985         status = rte_swx_ctl_pipeline_commit(p->ctl, 1);
1986         if (status)
1987                 snprintf(out, out_size, "Commit failed. "
1988                         "Use \"commit\" to retry or \"abort\" to discard the pending work.\n");
1989 }
1990
1991 static const char cmd_pipeline_abort_help[] =
1992 "pipeline <pipeline_name> abort\n";
1993
1994 static void
1995 cmd_pipeline_abort(char **tokens,
1996         uint32_t n_tokens,
1997         char *out,
1998         size_t out_size,
1999         void *obj)
2000 {
2001         struct pipeline *p;
2002         char *pipeline_name;
2003
2004         if (n_tokens != 3) {
2005                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2006                 return;
2007         }
2008
2009         pipeline_name = tokens[1];
2010         p = pipeline_find(obj, pipeline_name);
2011         if (!p || !p->ctl) {
2012                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2013                 return;
2014         }
2015
2016         rte_swx_ctl_pipeline_abort(p->ctl);
2017 }
2018
2019 static const char cmd_pipeline_regrd_help[] =
2020 "pipeline <pipeline_name> regrd <register_array_name> <index>\n";
2021
2022 static void
2023 cmd_pipeline_regrd(char **tokens,
2024         uint32_t n_tokens,
2025         char *out,
2026         size_t out_size,
2027         void *obj)
2028 {
2029         struct pipeline *p;
2030         const char *name;
2031         uint64_t value;
2032         uint32_t idx;
2033         int status;
2034
2035         if (n_tokens != 5) {
2036                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2037                 return;
2038         }
2039
2040         p = pipeline_find(obj, tokens[1]);
2041         if (!p || !p->ctl) {
2042                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2043                 return;
2044         }
2045
2046         if (strcmp(tokens[2], "regrd")) {
2047                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd");
2048                 return;
2049         }
2050
2051         name = tokens[3];
2052
2053         if (parser_read_uint32(&idx, tokens[4])) {
2054                 snprintf(out, out_size, MSG_ARG_INVALID, "index");
2055                 return;
2056         }
2057
2058         status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);
2059         if (status) {
2060                 snprintf(out, out_size, "Command failed.\n");
2061                 return;
2062         }
2063
2064         snprintf(out, out_size, "0x%" PRIx64 "\n", value);
2065 }
2066
2067 static const char cmd_pipeline_regwr_help[] =
2068 "pipeline <pipeline_name> regwr <register_array_name> <index> <value>\n";
2069
2070 static void
2071 cmd_pipeline_regwr(char **tokens,
2072         uint32_t n_tokens,
2073         char *out,
2074         size_t out_size,
2075         void *obj)
2076 {
2077         struct pipeline *p;
2078         const char *name;
2079         uint64_t value;
2080         uint32_t idx;
2081         int status;
2082
2083         if (n_tokens != 6) {
2084                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2085                 return;
2086         }
2087
2088         p = pipeline_find(obj, tokens[1]);
2089         if (!p || !p->ctl) {
2090                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2091                 return;
2092         }
2093
2094         if (strcmp(tokens[2], "regwr")) {
2095                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr");
2096                 return;
2097         }
2098
2099         name = tokens[3];
2100
2101         if (parser_read_uint32(&idx, tokens[4])) {
2102                 snprintf(out, out_size, MSG_ARG_INVALID, "index");
2103                 return;
2104         }
2105
2106         if (parser_read_uint64(&value, tokens[5])) {
2107                 snprintf(out, out_size, MSG_ARG_INVALID, "value");
2108                 return;
2109         }
2110
2111         status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);
2112         if (status) {
2113                 snprintf(out, out_size, "Command failed.\n");
2114                 return;
2115         }
2116 }
2117
2118 static const char cmd_pipeline_meter_profile_add_help[] =
2119 "pipeline <pipeline_name> meter profile <profile_name> add "
2120         "cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
2121
2122 static void
2123 cmd_pipeline_meter_profile_add(char **tokens,
2124         uint32_t n_tokens,
2125         char *out,
2126         size_t out_size,
2127         void *obj)
2128 {
2129         struct rte_meter_trtcm_params params;
2130         struct pipeline *p;
2131         const char *profile_name;
2132         int status;
2133
2134         if (n_tokens != 14) {
2135                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2136                 return;
2137         }
2138
2139         p = pipeline_find(obj, tokens[1]);
2140         if (!p || !p->ctl) {
2141                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2142                 return;
2143         }
2144
2145         if (strcmp(tokens[2], "meter")) {
2146                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2147                 return;
2148         }
2149
2150         if (strcmp(tokens[3], "profile")) {
2151                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
2152                 return;
2153         }
2154
2155         profile_name = tokens[4];
2156
2157         if (strcmp(tokens[5], "add")) {
2158                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
2159                 return;
2160         }
2161
2162         if (strcmp(tokens[6], "cir")) {
2163                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
2164                 return;
2165         }
2166
2167         if (parser_read_uint64(&params.cir, tokens[7])) {
2168                 snprintf(out, out_size, MSG_ARG_INVALID, "cir");
2169                 return;
2170         }
2171
2172         if (strcmp(tokens[8], "pir")) {
2173                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
2174                 return;
2175         }
2176
2177         if (parser_read_uint64(&params.pir, tokens[9])) {
2178                 snprintf(out, out_size, MSG_ARG_INVALID, "pir");
2179                 return;
2180         }
2181
2182         if (strcmp(tokens[10], "cbs")) {
2183                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
2184                 return;
2185         }
2186
2187         if (parser_read_uint64(&params.cbs, tokens[11])) {
2188                 snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
2189                 return;
2190         }
2191
2192         if (strcmp(tokens[12], "pbs")) {
2193                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
2194                 return;
2195         }
2196
2197         if (parser_read_uint64(&params.pbs, tokens[13])) {
2198                 snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
2199                 return;
2200         }
2201
2202         status = rte_swx_ctl_meter_profile_add(p->p, profile_name, &params);
2203         if (status) {
2204                 snprintf(out, out_size, "Command failed.\n");
2205                 return;
2206         }
2207 }
2208
2209 static const char cmd_pipeline_meter_profile_delete_help[] =
2210 "pipeline <pipeline_name> meter profile <profile_name> delete\n";
2211
2212 static void
2213 cmd_pipeline_meter_profile_delete(char **tokens,
2214         uint32_t n_tokens,
2215         char *out,
2216         size_t out_size,
2217         void *obj)
2218 {
2219         struct pipeline *p;
2220         const char *profile_name;
2221         int status;
2222
2223         if (n_tokens != 6) {
2224                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2225                 return;
2226         }
2227
2228         p = pipeline_find(obj, tokens[1]);
2229         if (!p || !p->ctl) {
2230                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2231                 return;
2232         }
2233
2234         if (strcmp(tokens[2], "meter")) {
2235                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2236                 return;
2237         }
2238
2239         if (strcmp(tokens[3], "profile")) {
2240                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
2241                 return;
2242         }
2243
2244         profile_name = tokens[4];
2245
2246         if (strcmp(tokens[5], "delete")) {
2247                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
2248                 return;
2249         }
2250
2251         status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
2252         if (status) {
2253                 snprintf(out, out_size, "Command failed.\n");
2254                 return;
2255         }
2256 }
2257
2258 static const char cmd_pipeline_meter_reset_help[] =
2259 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
2260         "reset\n";
2261
2262 static void
2263 cmd_pipeline_meter_reset(char **tokens,
2264         uint32_t n_tokens,
2265         char *out,
2266         size_t out_size,
2267         void *obj)
2268 {
2269         struct pipeline *p;
2270         const char *name;
2271         uint32_t idx0 = 0, idx1 = 0;
2272
2273         if (n_tokens != 9) {
2274                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2275                 return;
2276         }
2277
2278         p = pipeline_find(obj, tokens[1]);
2279         if (!p || !p->ctl) {
2280                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2281                 return;
2282         }
2283
2284         if (strcmp(tokens[2], "meter")) {
2285                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2286                 return;
2287         }
2288
2289         name = tokens[3];
2290
2291         if (strcmp(tokens[4], "from")) {
2292                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
2293                 return;
2294         }
2295
2296         if (parser_read_uint32(&idx0, tokens[5])) {
2297                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
2298                 return;
2299         }
2300
2301         if (strcmp(tokens[6], "to")) {
2302                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
2303                 return;
2304         }
2305
2306         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
2307                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
2308                 return;
2309         }
2310
2311         if (strcmp(tokens[8], "reset")) {
2312                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset");
2313                 return;
2314         }
2315
2316         for ( ; idx0 <= idx1; idx0++) {
2317                 int status;
2318
2319                 status = rte_swx_ctl_meter_reset(p->p, name, idx0);
2320                 if (status) {
2321                         snprintf(out, out_size, "Command failed for index %u.\n", idx0);
2322                         return;
2323                 }
2324         }
2325 }
2326
2327 static const char cmd_pipeline_meter_set_help[] =
2328 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
2329         "set profile <profile_name>\n";
2330
2331 static void
2332 cmd_pipeline_meter_set(char **tokens,
2333         uint32_t n_tokens,
2334         char *out,
2335         size_t out_size,
2336         void *obj)
2337 {
2338         struct pipeline *p;
2339         const char *name, *profile_name;
2340         uint32_t idx0 = 0, idx1 = 0;
2341
2342         if (n_tokens != 11) {
2343                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2344                 return;
2345         }
2346
2347         p = pipeline_find(obj, tokens[1]);
2348         if (!p || !p->ctl) {
2349                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2350                 return;
2351         }
2352
2353         if (strcmp(tokens[2], "meter")) {
2354                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2355                 return;
2356         }
2357
2358         name = tokens[3];
2359
2360         if (strcmp(tokens[4], "from")) {
2361                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
2362                 return;
2363         }
2364
2365         if (parser_read_uint32(&idx0, tokens[5])) {
2366                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
2367                 return;
2368         }
2369
2370         if (strcmp(tokens[6], "to")) {
2371                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
2372                 return;
2373         }
2374
2375         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
2376                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
2377                 return;
2378         }
2379
2380         if (strcmp(tokens[8], "set")) {
2381                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set");
2382                 return;
2383         }
2384
2385         if (strcmp(tokens[9], "profile")) {
2386                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
2387                 return;
2388         }
2389
2390         profile_name = tokens[10];
2391
2392         for ( ; idx0 <= idx1; idx0++) {
2393                 int status;
2394
2395                 status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
2396                 if (status) {
2397                         snprintf(out, out_size, "Command failed for index %u.\n", idx0);
2398                         return;
2399                 }
2400         }
2401 }
2402
2403 static const char cmd_pipeline_meter_stats_help[] =
2404 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
2405         "stats\n";
2406
2407 static void
2408 cmd_pipeline_meter_stats(char **tokens,
2409         uint32_t n_tokens,
2410         char *out,
2411         size_t out_size,
2412         void *obj)
2413 {
2414         struct rte_swx_ctl_meter_stats stats;
2415         struct pipeline *p;
2416         const char *name;
2417         uint32_t idx0 = 0, idx1 = 0;
2418
2419         if (n_tokens != 9) {
2420                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2421                 return;
2422         }
2423
2424         p = pipeline_find(obj, tokens[1]);
2425         if (!p || !p->ctl) {
2426                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2427                 return;
2428         }
2429
2430         if (strcmp(tokens[2], "meter")) {
2431                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2432                 return;
2433         }
2434
2435         name = tokens[3];
2436
2437         if (strcmp(tokens[4], "from")) {
2438                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
2439                 return;
2440         }
2441
2442         if (parser_read_uint32(&idx0, tokens[5])) {
2443                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
2444                 return;
2445         }
2446
2447         if (strcmp(tokens[6], "to")) {
2448                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
2449                 return;
2450         }
2451
2452         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
2453                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
2454                 return;
2455         }
2456
2457         if (strcmp(tokens[8], "stats")) {
2458                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2459                 return;
2460         }
2461
2462         /* Table header. */
2463         snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
2464                  "-------",
2465                  "----------------", "----------------", "----------------",
2466                  "----------------", "----------------", "----------------");
2467         out_size -= strlen(out);
2468         out += strlen(out);
2469
2470         snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n",
2471                  "METER #",
2472                  "GREEN (packets)", "YELLOW (packets)", "RED (packets)",
2473                  "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)");
2474         out_size -= strlen(out);
2475         out += strlen(out);
2476
2477         snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
2478                  "-------",
2479                  "----------------", "----------------", "----------------",
2480                  "----------------", "----------------", "----------------");
2481         out_size -= strlen(out);
2482         out += strlen(out);
2483
2484         /* Table rows. */
2485         for ( ; idx0 <= idx1; idx0++) {
2486                 int status;
2487
2488                 status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
2489                 if (status) {
2490                         snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
2491                         out_size -= strlen(out);
2492                         out += strlen(out);
2493                         return;
2494                 }
2495
2496                 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64
2497                          " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n",
2498                          idx0,
2499                          stats.n_pkts[RTE_COLOR_GREEN],
2500                          stats.n_pkts[RTE_COLOR_YELLOW],
2501                          stats.n_pkts[RTE_COLOR_RED],
2502                          stats.n_bytes[RTE_COLOR_GREEN],
2503                          stats.n_bytes[RTE_COLOR_YELLOW],
2504                          stats.n_bytes[RTE_COLOR_RED]);
2505                 out_size -= strlen(out);
2506                 out += strlen(out);
2507         }
2508 }
2509
2510 static const char cmd_pipeline_stats_help[] =
2511 "pipeline <pipeline_name> stats\n";
2512
2513 static void
2514 cmd_pipeline_stats(char **tokens,
2515         uint32_t n_tokens,
2516         char *out,
2517         size_t out_size,
2518         void *obj)
2519 {
2520         struct rte_swx_ctl_pipeline_info info;
2521         struct pipeline *p;
2522         uint32_t i;
2523         int status;
2524
2525         if (n_tokens != 3) {
2526                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2527                 return;
2528         }
2529
2530         p = pipeline_find(obj, tokens[1]);
2531         if (!p || !p->ctl) {
2532                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2533                 return;
2534         }
2535
2536         if (strcmp(tokens[2], "stats")) {
2537                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2538                 return;
2539         }
2540
2541         status = rte_swx_ctl_pipeline_info_get(p->p, &info);
2542         if (status) {
2543                 snprintf(out, out_size, "Pipeline info get error.");
2544                 return;
2545         }
2546
2547         snprintf(out, out_size, "Input ports:\n");
2548         out_size -= strlen(out);
2549         out += strlen(out);
2550
2551         for (i = 0; i < info.n_ports_in; i++) {
2552                 struct rte_swx_port_in_stats stats;
2553
2554                 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
2555
2556                 snprintf(out, out_size, "\tPort %u:"
2557                         " packets %" PRIu64
2558                         " bytes %" PRIu64
2559                         " empty %" PRIu64 "\n",
2560                         i, stats.n_pkts, stats.n_bytes, stats.n_empty);
2561                 out_size -= strlen(out);
2562                 out += strlen(out);
2563         }
2564
2565         snprintf(out, out_size, "\nOutput ports:\n");
2566         out_size -= strlen(out);
2567         out += strlen(out);
2568
2569         for (i = 0; i < info.n_ports_out; i++) {
2570                 struct rte_swx_port_out_stats stats;
2571
2572                 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
2573
2574                 if (i != info.n_ports_out - 1)
2575                         snprintf(out, out_size, "\tPort %u:", i);
2576                 else
2577                         snprintf(out, out_size, "\tDROP:");
2578
2579                 out_size -= strlen(out);
2580                 out += strlen(out);
2581
2582                 snprintf(out,
2583                         out_size,
2584                         " packets %" PRIu64
2585                         " bytes %" PRIu64
2586                         " clone %" PRIu64
2587                         " clonerr %" PRIu64 "\n",
2588                         stats.n_pkts,
2589                         stats.n_bytes,
2590                         stats.n_pkts_clone,
2591                         stats.n_pkts_clone_err);
2592
2593                 out_size -= strlen(out);
2594                 out += strlen(out);
2595         }
2596
2597         snprintf(out, out_size, "\nTables:\n");
2598         out_size -= strlen(out);
2599         out += strlen(out);
2600
2601         for (i = 0; i < info.n_tables; i++) {
2602                 struct rte_swx_ctl_table_info table_info;
2603                 uint64_t n_pkts_action[info.n_actions];
2604                 struct rte_swx_table_stats stats = {
2605                         .n_pkts_hit = 0,
2606                         .n_pkts_miss = 0,
2607                         .n_pkts_action = n_pkts_action,
2608                 };
2609                 uint32_t j;
2610
2611                 status = rte_swx_ctl_table_info_get(p->p, i, &table_info);
2612                 if (status) {
2613                         snprintf(out, out_size, "Table info get error.");
2614                         return;
2615                 }
2616
2617                 status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats);
2618                 if (status) {
2619                         snprintf(out, out_size, "Table stats read error.");
2620                         return;
2621                 }
2622
2623                 snprintf(out, out_size, "\tTable %s:\n"
2624                         "\t\tHit (packets): %" PRIu64 "\n"
2625                         "\t\tMiss (packets): %" PRIu64 "\n",
2626                         table_info.name,
2627                         stats.n_pkts_hit,
2628                         stats.n_pkts_miss);
2629                 out_size -= strlen(out);
2630                 out += strlen(out);
2631
2632                 for (j = 0; j < info.n_actions; j++) {
2633                         struct rte_swx_ctl_action_info action_info;
2634
2635                         status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
2636                         if (status) {
2637                                 snprintf(out, out_size, "Action info get error.");
2638                                 return;
2639                         }
2640
2641                         snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n",
2642                                 action_info.name,
2643                                 stats.n_pkts_action[j]);
2644                         out_size -= strlen(out);
2645                         out += strlen(out);
2646                 }
2647         }
2648
2649         snprintf(out, out_size, "\nLearner tables:\n");
2650         out_size -= strlen(out);
2651         out += strlen(out);
2652
2653         for (i = 0; i < info.n_learners; i++) {
2654                 struct rte_swx_ctl_learner_info learner_info;
2655                 uint64_t n_pkts_action[info.n_actions];
2656                 struct rte_swx_learner_stats stats = {
2657                         .n_pkts_hit = 0,
2658                         .n_pkts_miss = 0,
2659                         .n_pkts_action = n_pkts_action,
2660                 };
2661                 uint32_t j;
2662
2663                 status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info);
2664                 if (status) {
2665                         snprintf(out, out_size, "Learner table info get error.");
2666                         return;
2667                 }
2668
2669                 status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats);
2670                 if (status) {
2671                         snprintf(out, out_size, "Learner table stats read error.");
2672                         return;
2673                 }
2674
2675                 snprintf(out, out_size, "\tLearner table %s:\n"
2676                         "\t\tHit (packets): %" PRIu64 "\n"
2677                         "\t\tMiss (packets): %" PRIu64 "\n"
2678                         "\t\tLearn OK (packets): %" PRIu64 "\n"
2679                         "\t\tLearn error (packets): %" PRIu64 "\n"
2680                         "\t\tRearm (packets): %" PRIu64 "\n"
2681                         "\t\tForget (packets): %" PRIu64 "\n",
2682                         learner_info.name,
2683                         stats.n_pkts_hit,
2684                         stats.n_pkts_miss,
2685                         stats.n_pkts_learn_ok,
2686                         stats.n_pkts_learn_err,
2687                         stats.n_pkts_rearm,
2688                         stats.n_pkts_forget);
2689                 out_size -= strlen(out);
2690                 out += strlen(out);
2691
2692                 for (j = 0; j < info.n_actions; j++) {
2693                         struct rte_swx_ctl_action_info action_info;
2694
2695                         status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
2696                         if (status) {
2697                                 snprintf(out, out_size, "Action info get error.");
2698                                 return;
2699                         }
2700
2701                         snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n",
2702                                 action_info.name,
2703                                 stats.n_pkts_action[j]);
2704                         out_size -= strlen(out);
2705                         out += strlen(out);
2706                 }
2707         }
2708 }
2709
2710 static const char cmd_pipeline_mirror_help[] =
2711 "pipeline <pipeline_name> mirror slots <n_slots> sessions <n_sessions>\n";
2712
2713 static void
2714 cmd_pipeline_mirror(char **tokens,
2715         uint32_t n_tokens,
2716         char *out,
2717         size_t out_size,
2718         void *obj)
2719 {
2720         struct rte_swx_pipeline_mirroring_params params;
2721         struct pipeline *p;
2722         int status;
2723
2724         if (n_tokens != 7) {
2725                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2726                 return;
2727         }
2728
2729         if (strcmp(tokens[0], "pipeline")) {
2730                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2731                 return;
2732         }
2733
2734         p = pipeline_find(obj, tokens[1]);
2735         if (!p) {
2736                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2737                 return;
2738         }
2739
2740         if (strcmp(tokens[2], "mirror")) {
2741                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror");
2742                 return;
2743         }
2744
2745         if (strcmp(tokens[3], "slots")) {
2746                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "slots");
2747                 return;
2748         }
2749
2750         if (parser_read_uint32(&params.n_slots, tokens[4])) {
2751                 snprintf(out, out_size, MSG_ARG_INVALID, "n_slots");
2752                 return;
2753         }
2754
2755         if (strcmp(tokens[5], "sessions")) {
2756                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "sessions");
2757                 return;
2758         }
2759
2760         if (parser_read_uint32(&params.n_sessions, tokens[6])) {
2761                 snprintf(out, out_size, MSG_ARG_INVALID, "n_sessions");
2762                 return;
2763         }
2764
2765         status = rte_swx_pipeline_mirroring_config(p->p, &params);
2766         if (status) {
2767                 snprintf(out, out_size, "Command failed!\n");
2768                 return;
2769         }
2770 }
2771
2772 static const char cmd_pipeline_mirror_session_help[] =
2773 "pipeline <pipeline_name> mirror session <session_id> port <port_id> clone fast | slow "
2774 "truncate <truncation_length>\n";
2775
2776 static void
2777 cmd_pipeline_mirror_session(char **tokens,
2778         uint32_t n_tokens,
2779         char *out,
2780         size_t out_size,
2781         void *obj)
2782 {
2783         struct rte_swx_pipeline_mirroring_session_params params;
2784         struct pipeline *p;
2785         uint32_t session_id;
2786         int status;
2787
2788         if (n_tokens != 11) {
2789                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2790                 return;
2791         }
2792
2793         if (strcmp(tokens[0], "pipeline")) {
2794                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2795                 return;
2796         }
2797
2798         p = pipeline_find(obj, tokens[1]);
2799         if (!p || !p->ctl) {
2800                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2801                 return;
2802         }
2803
2804         if (strcmp(tokens[2], "mirror")) {
2805                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror");
2806                 return;
2807         }
2808
2809         if (strcmp(tokens[3], "session")) {
2810                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "session");
2811                 return;
2812         }
2813
2814         if (parser_read_uint32(&session_id, tokens[4])) {
2815                 snprintf(out, out_size, MSG_ARG_INVALID, "session_id");
2816                 return;
2817         }
2818
2819         if (strcmp(tokens[5], "port")) {
2820                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2821                 return;
2822         }
2823
2824         if (parser_read_uint32(&params.port_id, tokens[6])) {
2825                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2826                 return;
2827         }
2828
2829         if (strcmp(tokens[7], "clone")) {
2830                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "clone");
2831                 return;
2832         }
2833
2834         if (!strcmp(tokens[8], "fast"))
2835                 params.fast_clone = 1;
2836         else if (!strcmp(tokens[8], "slow"))
2837                 params.fast_clone = 0;
2838         else {
2839                 snprintf(out, out_size, MSG_ARG_INVALID, "clone");
2840                 return;
2841         }
2842
2843         if (strcmp(tokens[9], "truncate")) {
2844                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "truncate");
2845                 return;
2846         }
2847
2848         if (parser_read_uint32(&params.truncation_length, tokens[10])) {
2849                 snprintf(out, out_size, MSG_ARG_INVALID, "truncation_length");
2850                 return;
2851         }
2852
2853         status = rte_swx_ctl_pipeline_mirroring_session_set(p->p, session_id, &params);
2854         if (status) {
2855                 snprintf(out, out_size, "Command failed!\n");
2856                 return;
2857         }
2858 }
2859
2860 static const char cmd_thread_pipeline_enable_help[] =
2861 "thread <thread_id> pipeline <pipeline_name> enable\n";
2862
2863 static void
2864 cmd_thread_pipeline_enable(char **tokens,
2865         uint32_t n_tokens,
2866         char *out,
2867         size_t out_size,
2868         void *obj)
2869 {
2870         char *pipeline_name;
2871         struct pipeline *p;
2872         uint32_t thread_id;
2873         int status;
2874
2875         if (n_tokens != 5) {
2876                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2877                 return;
2878         }
2879
2880         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2881                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2882                 return;
2883         }
2884
2885         if (strcmp(tokens[2], "pipeline") != 0) {
2886                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2887                 return;
2888         }
2889
2890         pipeline_name = tokens[3];
2891         p = pipeline_find(obj, pipeline_name);
2892         if (!p || !p->ctl) {
2893                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2894                 return;
2895         }
2896
2897         if (strcmp(tokens[4], "enable") != 0) {
2898                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2899                 return;
2900         }
2901
2902         status = thread_pipeline_enable(thread_id, obj, pipeline_name);
2903         if (status) {
2904                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
2905                 return;
2906         }
2907 }
2908
2909 static const char cmd_thread_pipeline_disable_help[] =
2910 "thread <thread_id> pipeline <pipeline_name> disable\n";
2911
2912 static void
2913 cmd_thread_pipeline_disable(char **tokens,
2914         uint32_t n_tokens,
2915         char *out,
2916         size_t out_size,
2917         void *obj)
2918 {
2919         struct pipeline *p;
2920         char *pipeline_name;
2921         uint32_t thread_id;
2922         int status;
2923
2924         if (n_tokens != 5) {
2925                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2926                 return;
2927         }
2928
2929         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2930                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2931                 return;
2932         }
2933
2934         if (strcmp(tokens[2], "pipeline") != 0) {
2935                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2936                 return;
2937         }
2938
2939         pipeline_name = tokens[3];
2940         p = pipeline_find(obj, pipeline_name);
2941         if (!p || !p->ctl) {
2942                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2943                 return;
2944         }
2945
2946         if (strcmp(tokens[4], "disable") != 0) {
2947                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2948                 return;
2949         }
2950
2951         status = thread_pipeline_disable(thread_id, obj, pipeline_name);
2952         if (status) {
2953                 snprintf(out, out_size, MSG_CMD_FAIL,
2954                         "thread pipeline disable");
2955                 return;
2956         }
2957 }
2958
2959 static void
2960 cmd_help(char **tokens,
2961          uint32_t n_tokens,
2962          char *out,
2963          size_t out_size,
2964          void *arg __rte_unused)
2965 {
2966         tokens++;
2967         n_tokens--;
2968
2969         if (n_tokens == 0) {
2970                 snprintf(out, out_size,
2971                         "Type 'help <command>' for command details.\n\n"
2972                         "List of commands:\n"
2973                         "\tmempool\n"
2974                         "\tlink\n"
2975                         "\ttap\n"
2976                         "\tpipeline create\n"
2977                         "\tpipeline port in\n"
2978                         "\tpipeline port out\n"
2979                         "\tpipeline build\n"
2980                         "\tpipeline table add\n"
2981                         "\tpipeline table delete\n"
2982                         "\tpipeline table default\n"
2983                         "\tpipeline table show\n"
2984                         "\tpipeline selector group add\n"
2985                         "\tpipeline selector group delete\n"
2986                         "\tpipeline selector group member add\n"
2987                         "\tpipeline selector group member delete\n"
2988                         "\tpipeline selector show\n"
2989                         "\tpipeline learner default\n"
2990                         "\tpipeline commit\n"
2991                         "\tpipeline abort\n"
2992                         "\tpipeline regrd\n"
2993                         "\tpipeline regwr\n"
2994                         "\tpipeline meter profile add\n"
2995                         "\tpipeline meter profile delete\n"
2996                         "\tpipeline meter reset\n"
2997                         "\tpipeline meter set\n"
2998                         "\tpipeline meter stats\n"
2999                         "\tpipeline stats\n"
3000                         "\tpipeline mirror\n"
3001                         "\tpipeline mirror session\n"
3002                         "\tthread pipeline enable\n"
3003                         "\tthread pipeline disable\n\n");
3004                 return;
3005         }
3006
3007         if (strcmp(tokens[0], "mempool") == 0) {
3008                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
3009                 return;
3010         }
3011
3012         if (strcmp(tokens[0], "link") == 0) {
3013                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
3014                 return;
3015         }
3016
3017         if (strcmp(tokens[0], "ring") == 0) {
3018                 snprintf(out, out_size, "\n%s\n", cmd_ring_help);
3019                 return;
3020         }
3021
3022         if (strcmp(tokens[0], "tap") == 0) {
3023                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
3024                 return;
3025         }
3026
3027         if ((strcmp(tokens[0], "pipeline") == 0) &&
3028                 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
3029                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
3030                 return;
3031         }
3032
3033         if ((strcmp(tokens[0], "pipeline") == 0) &&
3034                 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
3035                 if (strcmp(tokens[2], "in") == 0) {
3036                         snprintf(out, out_size, "\n%s\n",
3037                                 cmd_pipeline_port_in_help);
3038                         return;
3039                 }
3040
3041                 if (strcmp(tokens[2], "out") == 0) {
3042                         snprintf(out, out_size, "\n%s\n",
3043                                 cmd_pipeline_port_out_help);
3044                         return;
3045                 }
3046         }
3047
3048         if ((strcmp(tokens[0], "pipeline") == 0) &&
3049                 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
3050                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
3051                 return;
3052         }
3053
3054         if ((strcmp(tokens[0], "pipeline") == 0) &&
3055                 (n_tokens == 3) &&
3056                 (strcmp(tokens[1], "table") == 0) &&
3057                 (strcmp(tokens[2], "add") == 0)) {
3058                 snprintf(out, out_size, "\n%s\n",
3059                         cmd_pipeline_table_add_help);
3060                 return;
3061         }
3062
3063         if ((strcmp(tokens[0], "pipeline") == 0) &&
3064                 (n_tokens == 3) &&
3065                 (strcmp(tokens[1], "table") == 0) &&
3066                 (strcmp(tokens[2], "delete") == 0)) {
3067                 snprintf(out, out_size, "\n%s\n",
3068                         cmd_pipeline_table_delete_help);
3069                 return;
3070         }
3071
3072         if ((strcmp(tokens[0], "pipeline") == 0) &&
3073                 (n_tokens == 3) &&
3074                 (strcmp(tokens[1], "table") == 0) &&
3075                 (strcmp(tokens[2], "default") == 0)) {
3076                 snprintf(out, out_size, "\n%s\n",
3077                         cmd_pipeline_table_default_help);
3078                 return;
3079         }
3080
3081         if ((strcmp(tokens[0], "pipeline") == 0) &&
3082                 (n_tokens == 3) &&
3083                 (strcmp(tokens[1], "table") == 0) &&
3084                 (strcmp(tokens[2], "show") == 0)) {
3085                 snprintf(out, out_size, "\n%s\n",
3086                         cmd_pipeline_table_show_help);
3087                 return;
3088         }
3089
3090         if ((strcmp(tokens[0], "pipeline") == 0) &&
3091                 (n_tokens == 4) &&
3092                 (strcmp(tokens[1], "selector") == 0) &&
3093                 (strcmp(tokens[2], "group") == 0) &&
3094                 (strcmp(tokens[3], "add") == 0)) {
3095                 snprintf(out, out_size, "\n%s\n",
3096                         cmd_pipeline_selector_group_add_help);
3097                 return;
3098         }
3099
3100         if ((strcmp(tokens[0], "pipeline") == 0) &&
3101                 (n_tokens == 4) &&
3102                 (strcmp(tokens[1], "selector") == 0) &&
3103                 (strcmp(tokens[2], "group") == 0) &&
3104                 (strcmp(tokens[3], "delete") == 0)) {
3105                 snprintf(out, out_size, "\n%s\n",
3106                         cmd_pipeline_selector_group_delete_help);
3107                 return;
3108         }
3109
3110         if ((strcmp(tokens[0], "pipeline") == 0) &&
3111                 (n_tokens == 5) &&
3112                 (strcmp(tokens[1], "selector") == 0) &&
3113                 (strcmp(tokens[2], "group") == 0) &&
3114                 (strcmp(tokens[3], "member") == 0) &&
3115                 (strcmp(tokens[4], "add") == 0)) {
3116                 snprintf(out, out_size, "\n%s\n",
3117                         cmd_pipeline_selector_group_member_add_help);
3118                 return;
3119         }
3120
3121         if ((strcmp(tokens[0], "pipeline") == 0) &&
3122                 (n_tokens == 5) &&
3123                 (strcmp(tokens[1], "selector") == 0) &&
3124                 (strcmp(tokens[2], "group") == 0) &&
3125                 (strcmp(tokens[3], "member") == 0) &&
3126                 (strcmp(tokens[4], "delete") == 0)) {
3127                 snprintf(out, out_size, "\n%s\n",
3128                         cmd_pipeline_selector_group_member_delete_help);
3129                 return;
3130         }
3131
3132         if ((strcmp(tokens[0], "pipeline") == 0) &&
3133                 (n_tokens == 3) &&
3134                 (strcmp(tokens[1], "selector") == 0) &&
3135                 (strcmp(tokens[2], "show") == 0)) {
3136                 snprintf(out, out_size, "\n%s\n",
3137                         cmd_pipeline_selector_show_help);
3138                 return;
3139         }
3140
3141         if ((strcmp(tokens[0], "pipeline") == 0) &&
3142                 (n_tokens == 3) &&
3143                 (strcmp(tokens[1], "learner") == 0) &&
3144                 (strcmp(tokens[2], "default") == 0)) {
3145                 snprintf(out, out_size, "\n%s\n",
3146                         cmd_pipeline_learner_default_help);
3147                 return;
3148         }
3149
3150         if ((strcmp(tokens[0], "pipeline") == 0) &&
3151                 (n_tokens == 2) &&
3152                 (strcmp(tokens[1], "commit") == 0)) {
3153                 snprintf(out, out_size, "\n%s\n",
3154                         cmd_pipeline_commit_help);
3155                 return;
3156         }
3157
3158         if ((strcmp(tokens[0], "pipeline") == 0) &&
3159                 (n_tokens == 2) &&
3160                 (strcmp(tokens[1], "abort") == 0)) {
3161                 snprintf(out, out_size, "\n%s\n",
3162                         cmd_pipeline_abort_help);
3163                 return;
3164         }
3165
3166         if ((strcmp(tokens[0], "pipeline") == 0) &&
3167                 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) {
3168                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help);
3169                 return;
3170         }
3171
3172         if ((strcmp(tokens[0], "pipeline") == 0) &&
3173                 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) {
3174                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help);
3175                 return;
3176         }
3177
3178         if (!strcmp(tokens[0], "pipeline") &&
3179                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
3180                 && !strcmp(tokens[2], "profile")
3181                 && !strcmp(tokens[3], "add")) {
3182                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help);
3183                 return;
3184         }
3185
3186         if (!strcmp(tokens[0], "pipeline") &&
3187                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
3188                 && !strcmp(tokens[2], "profile")
3189                 && !strcmp(tokens[3], "delete")) {
3190                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help);
3191                 return;
3192         }
3193
3194         if (!strcmp(tokens[0], "pipeline") &&
3195                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
3196                 && !strcmp(tokens[2], "reset")) {
3197                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help);
3198                 return;
3199         }
3200
3201         if (!strcmp(tokens[0], "pipeline") &&
3202                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
3203                 && !strcmp(tokens[2], "set")) {
3204                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help);
3205                 return;
3206         }
3207
3208         if (!strcmp(tokens[0], "pipeline") &&
3209                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
3210                 && !strcmp(tokens[2], "stats")) {
3211                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help);
3212                 return;
3213         }
3214
3215         if ((strcmp(tokens[0], "pipeline") == 0) &&
3216                 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) {
3217                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help);
3218                 return;
3219         }
3220
3221         if (!strcmp(tokens[0], "pipeline") &&
3222                 (n_tokens == 2) && !strcmp(tokens[1], "mirror")) {
3223                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_help);
3224                 return;
3225         }
3226
3227         if (!strcmp(tokens[0], "pipeline") &&
3228                 (n_tokens == 3) && !strcmp(tokens[1], "mirror")
3229                 && !strcmp(tokens[2], "session")) {
3230                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_session_help);
3231                 return;
3232         }
3233
3234         if ((n_tokens == 3) &&
3235                 (strcmp(tokens[0], "thread") == 0) &&
3236                 (strcmp(tokens[1], "pipeline") == 0)) {
3237                 if (strcmp(tokens[2], "enable") == 0) {
3238                         snprintf(out, out_size, "\n%s\n",
3239                                 cmd_thread_pipeline_enable_help);
3240                         return;
3241                 }
3242
3243                 if (strcmp(tokens[2], "disable") == 0) {
3244                         snprintf(out, out_size, "\n%s\n",
3245                                 cmd_thread_pipeline_disable_help);
3246                         return;
3247                 }
3248         }
3249
3250         snprintf(out, out_size, "Invalid command\n");
3251 }
3252
3253 void
3254 cli_process(char *in, char *out, size_t out_size, void *obj)
3255 {
3256         char *tokens[CMD_MAX_TOKENS];
3257         uint32_t n_tokens = RTE_DIM(tokens);
3258         int status;
3259
3260         if (is_comment(in))
3261                 return;
3262
3263         status = parse_tokenize_string(in, tokens, &n_tokens);
3264         if (status) {
3265                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
3266                 return;
3267         }
3268
3269         if (n_tokens == 0)
3270                 return;
3271
3272         if (strcmp(tokens[0], "help") == 0) {
3273                 cmd_help(tokens, n_tokens, out, out_size, obj);
3274                 return;
3275         }
3276
3277         if (strcmp(tokens[0], "mempool") == 0) {
3278                 cmd_mempool(tokens, n_tokens, out, out_size, obj);
3279                 return;
3280         }
3281
3282         if (strcmp(tokens[0], "link") == 0) {
3283                 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
3284                         cmd_link_show(tokens, n_tokens, out, out_size, obj);
3285                         return;
3286                 }
3287
3288                 cmd_link(tokens, n_tokens, out, out_size, obj);
3289                 return;
3290         }
3291
3292         if (strcmp(tokens[0], "ring") == 0) {
3293                 cmd_ring(tokens, n_tokens, out, out_size, obj);
3294                 return;
3295         }
3296
3297         if (strcmp(tokens[0], "tap") == 0) {
3298                 cmd_tap(tokens, n_tokens, out, out_size, obj);
3299                 return;
3300         }
3301
3302         if (strcmp(tokens[0], "pipeline") == 0) {
3303                 if ((n_tokens >= 3) &&
3304                         (strcmp(tokens[2], "create") == 0)) {
3305                         cmd_pipeline_create(tokens, n_tokens, out, out_size,
3306                                 obj);
3307                         return;
3308                 }
3309
3310                 if ((n_tokens >= 4) &&
3311                         (strcmp(tokens[2], "port") == 0) &&
3312                         (strcmp(tokens[3], "in") == 0)) {
3313                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
3314                                 obj);
3315                         return;
3316                 }
3317
3318                 if ((n_tokens >= 4) &&
3319                         (strcmp(tokens[2], "port") == 0) &&
3320                         (strcmp(tokens[3], "out") == 0)) {
3321                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
3322                                 obj);
3323                         return;
3324                 }
3325
3326                 if ((n_tokens >= 3) &&
3327                         (strcmp(tokens[2], "build") == 0)) {
3328                         cmd_pipeline_build(tokens, n_tokens, out, out_size,
3329                                 obj);
3330                         return;
3331                 }
3332
3333                 if ((n_tokens >= 5) &&
3334                         (strcmp(tokens[2], "table") == 0) &&
3335                         (strcmp(tokens[4], "add") == 0)) {
3336                         cmd_pipeline_table_add(tokens, n_tokens, out,
3337                                 out_size, obj);
3338                         return;
3339                 }
3340
3341                 if ((n_tokens >= 5) &&
3342                         (strcmp(tokens[2], "table") == 0) &&
3343                         (strcmp(tokens[4], "delete") == 0)) {
3344                         cmd_pipeline_table_delete(tokens, n_tokens, out,
3345                                 out_size, obj);
3346                         return;
3347                 }
3348
3349                 if ((n_tokens >= 5) &&
3350                         (strcmp(tokens[2], "table") == 0) &&
3351                         (strcmp(tokens[4], "default") == 0)) {
3352                         cmd_pipeline_table_default(tokens, n_tokens, out,
3353                                 out_size, obj);
3354                         return;
3355                 }
3356
3357                 if ((n_tokens >= 5) &&
3358                         (strcmp(tokens[2], "table") == 0) &&
3359                         (strcmp(tokens[4], "show") == 0)) {
3360                         cmd_pipeline_table_show(tokens, n_tokens, out,
3361                                 out_size, obj);
3362                         return;
3363                 }
3364
3365                 if ((n_tokens >= 6) &&
3366                         (strcmp(tokens[2], "selector") == 0) &&
3367                         (strcmp(tokens[4], "group") == 0) &&
3368                         (strcmp(tokens[5], "add") == 0)) {
3369                         cmd_pipeline_selector_group_add(tokens, n_tokens, out,
3370                                 out_size, obj);
3371                         return;
3372                 }
3373
3374                 if ((n_tokens >= 6) &&
3375                         (strcmp(tokens[2], "selector") == 0) &&
3376                         (strcmp(tokens[4], "group") == 0) &&
3377                         (strcmp(tokens[5], "delete") == 0)) {
3378                         cmd_pipeline_selector_group_delete(tokens, n_tokens, out,
3379                                 out_size, obj);
3380                         return;
3381                 }
3382
3383                 if ((n_tokens >= 7) &&
3384                         (strcmp(tokens[2], "selector") == 0) &&
3385                         (strcmp(tokens[4], "group") == 0) &&
3386                         (strcmp(tokens[5], "member") == 0) &&
3387                         (strcmp(tokens[6], "add") == 0)) {
3388                         cmd_pipeline_selector_group_member_add(tokens, n_tokens, out,
3389                                 out_size, obj);
3390                         return;
3391                 }
3392
3393                 if ((n_tokens >= 7) &&
3394                         (strcmp(tokens[2], "selector") == 0) &&
3395                         (strcmp(tokens[4], "group") == 0) &&
3396                         (strcmp(tokens[5], "member") == 0) &&
3397                         (strcmp(tokens[6], "delete") == 0)) {
3398                         cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out,
3399                                 out_size, obj);
3400                         return;
3401                 }
3402
3403                 if ((n_tokens >= 5) &&
3404                         (strcmp(tokens[2], "selector") == 0) &&
3405                         (strcmp(tokens[4], "show") == 0)) {
3406                         cmd_pipeline_selector_show(tokens, n_tokens, out,
3407                                 out_size, obj);
3408                         return;
3409                 }
3410
3411                 if ((n_tokens >= 5) &&
3412                         (strcmp(tokens[2], "learner") == 0) &&
3413                         (strcmp(tokens[4], "default") == 0)) {
3414                         cmd_pipeline_learner_default(tokens, n_tokens, out,
3415                                 out_size, obj);
3416                         return;
3417                 }
3418
3419                 if ((n_tokens >= 3) &&
3420                         (strcmp(tokens[2], "commit") == 0)) {
3421                         cmd_pipeline_commit(tokens, n_tokens, out,
3422                                 out_size, obj);
3423                         return;
3424                 }
3425
3426                 if ((n_tokens >= 3) &&
3427                         (strcmp(tokens[2], "abort") == 0)) {
3428                         cmd_pipeline_abort(tokens, n_tokens, out,
3429                                 out_size, obj);
3430                         return;
3431                 }
3432
3433                 if ((n_tokens >= 3) &&
3434                         (strcmp(tokens[2], "regrd") == 0)) {
3435                         cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj);
3436                         return;
3437                 }
3438
3439                 if ((n_tokens >= 3) &&
3440                         (strcmp(tokens[2], "regwr") == 0)) {
3441                         cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj);
3442                         return;
3443                 }
3444
3445                 if ((n_tokens >= 6) &&
3446                         (strcmp(tokens[2], "meter") == 0) &&
3447                         (strcmp(tokens[3], "profile") == 0) &&
3448                         (strcmp(tokens[5], "add") == 0)) {
3449                         cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj);
3450                         return;
3451                 }
3452
3453                 if ((n_tokens >= 6) &&
3454                         (strcmp(tokens[2], "meter") == 0) &&
3455                         (strcmp(tokens[3], "profile") == 0) &&
3456                         (strcmp(tokens[5], "delete") == 0)) {
3457                         cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj);
3458                         return;
3459                 }
3460
3461                 if ((n_tokens >= 9) &&
3462                         (strcmp(tokens[2], "meter") == 0) &&
3463                         (strcmp(tokens[8], "reset") == 0)) {
3464                         cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj);
3465                         return;
3466                 }
3467
3468                 if ((n_tokens >= 9) &&
3469                         (strcmp(tokens[2], "meter") == 0) &&
3470                         (strcmp(tokens[8], "set") == 0)) {
3471                         cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj);
3472                         return;
3473                 }
3474
3475                 if ((n_tokens >= 9) &&
3476                         (strcmp(tokens[2], "meter") == 0) &&
3477                         (strcmp(tokens[8], "stats") == 0)) {
3478                         cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj);
3479                         return;
3480                 }
3481
3482                 if ((n_tokens >= 3) &&
3483                         (strcmp(tokens[2], "stats") == 0)) {
3484                         cmd_pipeline_stats(tokens, n_tokens, out, out_size,
3485                                 obj);
3486                         return;
3487                 }
3488
3489                 if ((n_tokens >= 4) &&
3490                         (strcmp(tokens[2], "mirror") == 0) &&
3491                         (strcmp(tokens[3], "slots") == 0)) {
3492                         cmd_pipeline_mirror(tokens, n_tokens, out, out_size, obj);
3493                         return;
3494                 }
3495
3496                 if ((n_tokens >= 4) &&
3497                         (strcmp(tokens[2], "mirror") == 0) &&
3498                         (strcmp(tokens[3], "session") == 0)) {
3499                         cmd_pipeline_mirror_session(tokens, n_tokens, out, out_size, obj);
3500                         return;
3501                 }
3502         }
3503
3504         if (strcmp(tokens[0], "thread") == 0) {
3505                 if ((n_tokens >= 5) &&
3506                         (strcmp(tokens[4], "enable") == 0)) {
3507                         cmd_thread_pipeline_enable(tokens, n_tokens,
3508                                 out, out_size, obj);
3509                         return;
3510                 }
3511
3512                 if ((n_tokens >= 5) &&
3513                         (strcmp(tokens[4], "disable") == 0)) {
3514                         cmd_thread_pipeline_disable(tokens, n_tokens,
3515                                 out, out_size, obj);
3516                         return;
3517                 }
3518         }
3519
3520         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
3521 }
3522
3523 int
3524 cli_script_process(const char *file_name,
3525         size_t msg_in_len_max,
3526         size_t msg_out_len_max,
3527         void *obj)
3528 {
3529         char *msg_in = NULL, *msg_out = NULL;
3530         FILE *f = NULL;
3531
3532         /* Check input arguments */
3533         if ((file_name == NULL) ||
3534                 (strlen(file_name) == 0) ||
3535                 (msg_in_len_max == 0) ||
3536                 (msg_out_len_max == 0))
3537                 return -EINVAL;
3538
3539         msg_in = malloc(msg_in_len_max + 1);
3540         msg_out = malloc(msg_out_len_max + 1);
3541         if ((msg_in == NULL) ||
3542                 (msg_out == NULL)) {
3543                 free(msg_out);
3544                 free(msg_in);
3545                 return -ENOMEM;
3546         }
3547
3548         /* Open input file */
3549         f = fopen(file_name, "r");
3550         if (f == NULL) {
3551                 free(msg_out);
3552                 free(msg_in);
3553                 return -EIO;
3554         }
3555
3556         /* Read file */
3557         for ( ; ; ) {
3558                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
3559                         break;
3560
3561                 printf("%s", msg_in);
3562                 msg_out[0] = 0;
3563
3564                 cli_process(msg_in,
3565                         msg_out,
3566                         msg_out_len_max,
3567                         obj);
3568
3569                 if (strlen(msg_out))
3570                         printf("%s", msg_out);
3571         }
3572
3573         /* Close file */
3574         fclose(f);
3575         free(msg_out);
3576         free(msg_in);
3577         return 0;
3578 }