examples/pipeline: print table entries to file
[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:"
2576                                 " packets %" PRIu64
2577                                 " bytes %" PRIu64 "\n",
2578                                 i, stats.n_pkts, stats.n_bytes);
2579                 else
2580                         snprintf(out, out_size, "\tDROP:"
2581                                 " packets %" PRIu64
2582                                 " bytes %" PRIu64 "\n",
2583                                 stats.n_pkts, stats.n_bytes);
2584
2585                 out_size -= strlen(out);
2586                 out += strlen(out);
2587         }
2588
2589         snprintf(out, out_size, "\nTables:\n");
2590         out_size -= strlen(out);
2591         out += strlen(out);
2592
2593         for (i = 0; i < info.n_tables; i++) {
2594                 struct rte_swx_ctl_table_info table_info;
2595                 uint64_t n_pkts_action[info.n_actions];
2596                 struct rte_swx_table_stats stats = {
2597                         .n_pkts_hit = 0,
2598                         .n_pkts_miss = 0,
2599                         .n_pkts_action = n_pkts_action,
2600                 };
2601                 uint32_t j;
2602
2603                 status = rte_swx_ctl_table_info_get(p->p, i, &table_info);
2604                 if (status) {
2605                         snprintf(out, out_size, "Table info get error.");
2606                         return;
2607                 }
2608
2609                 status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats);
2610                 if (status) {
2611                         snprintf(out, out_size, "Table stats read error.");
2612                         return;
2613                 }
2614
2615                 snprintf(out, out_size, "\tTable %s:\n"
2616                         "\t\tHit (packets): %" PRIu64 "\n"
2617                         "\t\tMiss (packets): %" PRIu64 "\n",
2618                         table_info.name,
2619                         stats.n_pkts_hit,
2620                         stats.n_pkts_miss);
2621                 out_size -= strlen(out);
2622                 out += strlen(out);
2623
2624                 for (j = 0; j < info.n_actions; j++) {
2625                         struct rte_swx_ctl_action_info action_info;
2626
2627                         status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
2628                         if (status) {
2629                                 snprintf(out, out_size, "Action info get error.");
2630                                 return;
2631                         }
2632
2633                         snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n",
2634                                 action_info.name,
2635                                 stats.n_pkts_action[j]);
2636                         out_size -= strlen(out);
2637                         out += strlen(out);
2638                 }
2639         }
2640
2641         snprintf(out, out_size, "\nLearner tables:\n");
2642         out_size -= strlen(out);
2643         out += strlen(out);
2644
2645         for (i = 0; i < info.n_learners; i++) {
2646                 struct rte_swx_ctl_learner_info learner_info;
2647                 uint64_t n_pkts_action[info.n_actions];
2648                 struct rte_swx_learner_stats stats = {
2649                         .n_pkts_hit = 0,
2650                         .n_pkts_miss = 0,
2651                         .n_pkts_action = n_pkts_action,
2652                 };
2653                 uint32_t j;
2654
2655                 status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info);
2656                 if (status) {
2657                         snprintf(out, out_size, "Learner table info get error.");
2658                         return;
2659                 }
2660
2661                 status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats);
2662                 if (status) {
2663                         snprintf(out, out_size, "Learner table stats read error.");
2664                         return;
2665                 }
2666
2667                 snprintf(out, out_size, "\tLearner table %s:\n"
2668                         "\t\tHit (packets): %" PRIu64 "\n"
2669                         "\t\tMiss (packets): %" PRIu64 "\n"
2670                         "\t\tLearn OK (packets): %" PRIu64 "\n"
2671                         "\t\tLearn error (packets): %" PRIu64 "\n"
2672                         "\t\tForget (packets): %" PRIu64 "\n",
2673                         learner_info.name,
2674                         stats.n_pkts_hit,
2675                         stats.n_pkts_miss,
2676                         stats.n_pkts_learn_ok,
2677                         stats.n_pkts_learn_err,
2678                         stats.n_pkts_forget);
2679                 out_size -= strlen(out);
2680                 out += strlen(out);
2681
2682                 for (j = 0; j < info.n_actions; j++) {
2683                         struct rte_swx_ctl_action_info action_info;
2684
2685                         status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
2686                         if (status) {
2687                                 snprintf(out, out_size, "Action info get error.");
2688                                 return;
2689                         }
2690
2691                         snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n",
2692                                 action_info.name,
2693                                 stats.n_pkts_action[j]);
2694                         out_size -= strlen(out);
2695                         out += strlen(out);
2696                 }
2697         }
2698 }
2699
2700 static const char cmd_thread_pipeline_enable_help[] =
2701 "thread <thread_id> pipeline <pipeline_name> enable\n";
2702
2703 static void
2704 cmd_thread_pipeline_enable(char **tokens,
2705         uint32_t n_tokens,
2706         char *out,
2707         size_t out_size,
2708         void *obj)
2709 {
2710         char *pipeline_name;
2711         struct pipeline *p;
2712         uint32_t thread_id;
2713         int status;
2714
2715         if (n_tokens != 5) {
2716                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2717                 return;
2718         }
2719
2720         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2721                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2722                 return;
2723         }
2724
2725         if (strcmp(tokens[2], "pipeline") != 0) {
2726                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2727                 return;
2728         }
2729
2730         pipeline_name = tokens[3];
2731         p = pipeline_find(obj, pipeline_name);
2732         if (!p || !p->ctl) {
2733                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2734                 return;
2735         }
2736
2737         if (strcmp(tokens[4], "enable") != 0) {
2738                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2739                 return;
2740         }
2741
2742         status = thread_pipeline_enable(thread_id, obj, pipeline_name);
2743         if (status) {
2744                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
2745                 return;
2746         }
2747 }
2748
2749 static const char cmd_thread_pipeline_disable_help[] =
2750 "thread <thread_id> pipeline <pipeline_name> disable\n";
2751
2752 static void
2753 cmd_thread_pipeline_disable(char **tokens,
2754         uint32_t n_tokens,
2755         char *out,
2756         size_t out_size,
2757         void *obj)
2758 {
2759         struct pipeline *p;
2760         char *pipeline_name;
2761         uint32_t thread_id;
2762         int status;
2763
2764         if (n_tokens != 5) {
2765                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2766                 return;
2767         }
2768
2769         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2770                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2771                 return;
2772         }
2773
2774         if (strcmp(tokens[2], "pipeline") != 0) {
2775                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2776                 return;
2777         }
2778
2779         pipeline_name = tokens[3];
2780         p = pipeline_find(obj, pipeline_name);
2781         if (!p || !p->ctl) {
2782                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2783                 return;
2784         }
2785
2786         if (strcmp(tokens[4], "disable") != 0) {
2787                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2788                 return;
2789         }
2790
2791         status = thread_pipeline_disable(thread_id, obj, pipeline_name);
2792         if (status) {
2793                 snprintf(out, out_size, MSG_CMD_FAIL,
2794                         "thread pipeline disable");
2795                 return;
2796         }
2797 }
2798
2799 static void
2800 cmd_help(char **tokens,
2801          uint32_t n_tokens,
2802          char *out,
2803          size_t out_size,
2804          void *arg __rte_unused)
2805 {
2806         tokens++;
2807         n_tokens--;
2808
2809         if (n_tokens == 0) {
2810                 snprintf(out, out_size,
2811                         "Type 'help <command>' for command details.\n\n"
2812                         "List of commands:\n"
2813                         "\tmempool\n"
2814                         "\tlink\n"
2815                         "\ttap\n"
2816                         "\tpipeline create\n"
2817                         "\tpipeline port in\n"
2818                         "\tpipeline port out\n"
2819                         "\tpipeline build\n"
2820                         "\tpipeline table add\n"
2821                         "\tpipeline table delete\n"
2822                         "\tpipeline table default\n"
2823                         "\tpipeline table show\n"
2824                         "\tpipeline selector group add\n"
2825                         "\tpipeline selector group delete\n"
2826                         "\tpipeline selector group member add\n"
2827                         "\tpipeline selector group member delete\n"
2828                         "\tpipeline selector show\n"
2829                         "\tpipeline learner default\n"
2830                         "\tpipeline commit\n"
2831                         "\tpipeline abort\n"
2832                         "\tpipeline regrd\n"
2833                         "\tpipeline regwr\n"
2834                         "\tpipeline meter profile add\n"
2835                         "\tpipeline meter profile delete\n"
2836                         "\tpipeline meter reset\n"
2837                         "\tpipeline meter set\n"
2838                         "\tpipeline meter stats\n"
2839                         "\tpipeline stats\n"
2840                         "\tthread pipeline enable\n"
2841                         "\tthread pipeline disable\n\n");
2842                 return;
2843         }
2844
2845         if (strcmp(tokens[0], "mempool") == 0) {
2846                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
2847                 return;
2848         }
2849
2850         if (strcmp(tokens[0], "link") == 0) {
2851                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
2852                 return;
2853         }
2854
2855         if (strcmp(tokens[0], "ring") == 0) {
2856                 snprintf(out, out_size, "\n%s\n", cmd_ring_help);
2857                 return;
2858         }
2859
2860         if (strcmp(tokens[0], "tap") == 0) {
2861                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
2862                 return;
2863         }
2864
2865         if ((strcmp(tokens[0], "pipeline") == 0) &&
2866                 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
2867                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
2868                 return;
2869         }
2870
2871         if ((strcmp(tokens[0], "pipeline") == 0) &&
2872                 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
2873                 if (strcmp(tokens[2], "in") == 0) {
2874                         snprintf(out, out_size, "\n%s\n",
2875                                 cmd_pipeline_port_in_help);
2876                         return;
2877                 }
2878
2879                 if (strcmp(tokens[2], "out") == 0) {
2880                         snprintf(out, out_size, "\n%s\n",
2881                                 cmd_pipeline_port_out_help);
2882                         return;
2883                 }
2884         }
2885
2886         if ((strcmp(tokens[0], "pipeline") == 0) &&
2887                 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
2888                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
2889                 return;
2890         }
2891
2892         if ((strcmp(tokens[0], "pipeline") == 0) &&
2893                 (n_tokens == 3) &&
2894                 (strcmp(tokens[1], "table") == 0) &&
2895                 (strcmp(tokens[2], "add") == 0)) {
2896                 snprintf(out, out_size, "\n%s\n",
2897                         cmd_pipeline_table_add_help);
2898                 return;
2899         }
2900
2901         if ((strcmp(tokens[0], "pipeline") == 0) &&
2902                 (n_tokens == 3) &&
2903                 (strcmp(tokens[1], "table") == 0) &&
2904                 (strcmp(tokens[2], "delete") == 0)) {
2905                 snprintf(out, out_size, "\n%s\n",
2906                         cmd_pipeline_table_delete_help);
2907                 return;
2908         }
2909
2910         if ((strcmp(tokens[0], "pipeline") == 0) &&
2911                 (n_tokens == 3) &&
2912                 (strcmp(tokens[1], "table") == 0) &&
2913                 (strcmp(tokens[2], "default") == 0)) {
2914                 snprintf(out, out_size, "\n%s\n",
2915                         cmd_pipeline_table_default_help);
2916                 return;
2917         }
2918
2919         if ((strcmp(tokens[0], "pipeline") == 0) &&
2920                 (n_tokens == 3) &&
2921                 (strcmp(tokens[1], "table") == 0) &&
2922                 (strcmp(tokens[2], "show") == 0)) {
2923                 snprintf(out, out_size, "\n%s\n",
2924                         cmd_pipeline_table_show_help);
2925                 return;
2926         }
2927
2928         if ((strcmp(tokens[0], "pipeline") == 0) &&
2929                 (n_tokens == 4) &&
2930                 (strcmp(tokens[1], "selector") == 0) &&
2931                 (strcmp(tokens[2], "group") == 0) &&
2932                 (strcmp(tokens[3], "add") == 0)) {
2933                 snprintf(out, out_size, "\n%s\n",
2934                         cmd_pipeline_selector_group_add_help);
2935                 return;
2936         }
2937
2938         if ((strcmp(tokens[0], "pipeline") == 0) &&
2939                 (n_tokens == 4) &&
2940                 (strcmp(tokens[1], "selector") == 0) &&
2941                 (strcmp(tokens[2], "group") == 0) &&
2942                 (strcmp(tokens[3], "delete") == 0)) {
2943                 snprintf(out, out_size, "\n%s\n",
2944                         cmd_pipeline_selector_group_delete_help);
2945                 return;
2946         }
2947
2948         if ((strcmp(tokens[0], "pipeline") == 0) &&
2949                 (n_tokens == 5) &&
2950                 (strcmp(tokens[1], "selector") == 0) &&
2951                 (strcmp(tokens[2], "group") == 0) &&
2952                 (strcmp(tokens[3], "member") == 0) &&
2953                 (strcmp(tokens[4], "add") == 0)) {
2954                 snprintf(out, out_size, "\n%s\n",
2955                         cmd_pipeline_selector_group_member_add_help);
2956                 return;
2957         }
2958
2959         if ((strcmp(tokens[0], "pipeline") == 0) &&
2960                 (n_tokens == 5) &&
2961                 (strcmp(tokens[1], "selector") == 0) &&
2962                 (strcmp(tokens[2], "group") == 0) &&
2963                 (strcmp(tokens[3], "member") == 0) &&
2964                 (strcmp(tokens[4], "delete") == 0)) {
2965                 snprintf(out, out_size, "\n%s\n",
2966                         cmd_pipeline_selector_group_member_delete_help);
2967                 return;
2968         }
2969
2970         if ((strcmp(tokens[0], "pipeline") == 0) &&
2971                 (n_tokens == 3) &&
2972                 (strcmp(tokens[1], "selector") == 0) &&
2973                 (strcmp(tokens[2], "show") == 0)) {
2974                 snprintf(out, out_size, "\n%s\n",
2975                         cmd_pipeline_selector_show_help);
2976                 return;
2977         }
2978
2979         if ((strcmp(tokens[0], "pipeline") == 0) &&
2980                 (n_tokens == 3) &&
2981                 (strcmp(tokens[1], "learner") == 0) &&
2982                 (strcmp(tokens[2], "default") == 0)) {
2983                 snprintf(out, out_size, "\n%s\n",
2984                         cmd_pipeline_learner_default_help);
2985                 return;
2986         }
2987
2988         if ((strcmp(tokens[0], "pipeline") == 0) &&
2989                 (n_tokens == 2) &&
2990                 (strcmp(tokens[1], "commit") == 0)) {
2991                 snprintf(out, out_size, "\n%s\n",
2992                         cmd_pipeline_commit_help);
2993                 return;
2994         }
2995
2996         if ((strcmp(tokens[0], "pipeline") == 0) &&
2997                 (n_tokens == 2) &&
2998                 (strcmp(tokens[1], "abort") == 0)) {
2999                 snprintf(out, out_size, "\n%s\n",
3000                         cmd_pipeline_abort_help);
3001                 return;
3002         }
3003
3004         if ((strcmp(tokens[0], "pipeline") == 0) &&
3005                 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) {
3006                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help);
3007                 return;
3008         }
3009
3010         if ((strcmp(tokens[0], "pipeline") == 0) &&
3011                 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) {
3012                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help);
3013                 return;
3014         }
3015
3016         if (!strcmp(tokens[0], "pipeline") &&
3017                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
3018                 && !strcmp(tokens[2], "profile")
3019                 && !strcmp(tokens[3], "add")) {
3020                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help);
3021                 return;
3022         }
3023
3024         if (!strcmp(tokens[0], "pipeline") &&
3025                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
3026                 && !strcmp(tokens[2], "profile")
3027                 && !strcmp(tokens[3], "delete")) {
3028                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help);
3029                 return;
3030         }
3031
3032         if (!strcmp(tokens[0], "pipeline") &&
3033                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
3034                 && !strcmp(tokens[2], "reset")) {
3035                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help);
3036                 return;
3037         }
3038
3039         if (!strcmp(tokens[0], "pipeline") &&
3040                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
3041                 && !strcmp(tokens[2], "set")) {
3042                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help);
3043                 return;
3044         }
3045
3046         if (!strcmp(tokens[0], "pipeline") &&
3047                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
3048                 && !strcmp(tokens[2], "stats")) {
3049                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help);
3050                 return;
3051         }
3052
3053         if ((strcmp(tokens[0], "pipeline") == 0) &&
3054                 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) {
3055                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help);
3056                 return;
3057         }
3058
3059         if ((n_tokens == 3) &&
3060                 (strcmp(tokens[0], "thread") == 0) &&
3061                 (strcmp(tokens[1], "pipeline") == 0)) {
3062                 if (strcmp(tokens[2], "enable") == 0) {
3063                         snprintf(out, out_size, "\n%s\n",
3064                                 cmd_thread_pipeline_enable_help);
3065                         return;
3066                 }
3067
3068                 if (strcmp(tokens[2], "disable") == 0) {
3069                         snprintf(out, out_size, "\n%s\n",
3070                                 cmd_thread_pipeline_disable_help);
3071                         return;
3072                 }
3073         }
3074
3075         snprintf(out, out_size, "Invalid command\n");
3076 }
3077
3078 void
3079 cli_process(char *in, char *out, size_t out_size, void *obj)
3080 {
3081         char *tokens[CMD_MAX_TOKENS];
3082         uint32_t n_tokens = RTE_DIM(tokens);
3083         int status;
3084
3085         if (is_comment(in))
3086                 return;
3087
3088         status = parse_tokenize_string(in, tokens, &n_tokens);
3089         if (status) {
3090                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
3091                 return;
3092         }
3093
3094         if (n_tokens == 0)
3095                 return;
3096
3097         if (strcmp(tokens[0], "help") == 0) {
3098                 cmd_help(tokens, n_tokens, out, out_size, obj);
3099                 return;
3100         }
3101
3102         if (strcmp(tokens[0], "mempool") == 0) {
3103                 cmd_mempool(tokens, n_tokens, out, out_size, obj);
3104                 return;
3105         }
3106
3107         if (strcmp(tokens[0], "link") == 0) {
3108                 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
3109                         cmd_link_show(tokens, n_tokens, out, out_size, obj);
3110                         return;
3111                 }
3112
3113                 cmd_link(tokens, n_tokens, out, out_size, obj);
3114                 return;
3115         }
3116
3117         if (strcmp(tokens[0], "ring") == 0) {
3118                 cmd_ring(tokens, n_tokens, out, out_size, obj);
3119                 return;
3120         }
3121
3122         if (strcmp(tokens[0], "tap") == 0) {
3123                 cmd_tap(tokens, n_tokens, out, out_size, obj);
3124                 return;
3125         }
3126
3127         if (strcmp(tokens[0], "pipeline") == 0) {
3128                 if ((n_tokens >= 3) &&
3129                         (strcmp(tokens[2], "create") == 0)) {
3130                         cmd_pipeline_create(tokens, n_tokens, out, out_size,
3131                                 obj);
3132                         return;
3133                 }
3134
3135                 if ((n_tokens >= 4) &&
3136                         (strcmp(tokens[2], "port") == 0) &&
3137                         (strcmp(tokens[3], "in") == 0)) {
3138                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
3139                                 obj);
3140                         return;
3141                 }
3142
3143                 if ((n_tokens >= 4) &&
3144                         (strcmp(tokens[2], "port") == 0) &&
3145                         (strcmp(tokens[3], "out") == 0)) {
3146                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
3147                                 obj);
3148                         return;
3149                 }
3150
3151                 if ((n_tokens >= 3) &&
3152                         (strcmp(tokens[2], "build") == 0)) {
3153                         cmd_pipeline_build(tokens, n_tokens, out, out_size,
3154                                 obj);
3155                         return;
3156                 }
3157
3158                 if ((n_tokens >= 5) &&
3159                         (strcmp(tokens[2], "table") == 0) &&
3160                         (strcmp(tokens[4], "add") == 0)) {
3161                         cmd_pipeline_table_add(tokens, n_tokens, out,
3162                                 out_size, obj);
3163                         return;
3164                 }
3165
3166                 if ((n_tokens >= 5) &&
3167                         (strcmp(tokens[2], "table") == 0) &&
3168                         (strcmp(tokens[4], "delete") == 0)) {
3169                         cmd_pipeline_table_delete(tokens, n_tokens, out,
3170                                 out_size, obj);
3171                         return;
3172                 }
3173
3174                 if ((n_tokens >= 5) &&
3175                         (strcmp(tokens[2], "table") == 0) &&
3176                         (strcmp(tokens[4], "default") == 0)) {
3177                         cmd_pipeline_table_default(tokens, n_tokens, out,
3178                                 out_size, obj);
3179                         return;
3180                 }
3181
3182                 if ((n_tokens >= 5) &&
3183                         (strcmp(tokens[2], "table") == 0) &&
3184                         (strcmp(tokens[4], "show") == 0)) {
3185                         cmd_pipeline_table_show(tokens, n_tokens, out,
3186                                 out_size, obj);
3187                         return;
3188                 }
3189
3190                 if ((n_tokens >= 6) &&
3191                         (strcmp(tokens[2], "selector") == 0) &&
3192                         (strcmp(tokens[4], "group") == 0) &&
3193                         (strcmp(tokens[5], "add") == 0)) {
3194                         cmd_pipeline_selector_group_add(tokens, n_tokens, out,
3195                                 out_size, obj);
3196                         return;
3197                 }
3198
3199                 if ((n_tokens >= 6) &&
3200                         (strcmp(tokens[2], "selector") == 0) &&
3201                         (strcmp(tokens[4], "group") == 0) &&
3202                         (strcmp(tokens[5], "delete") == 0)) {
3203                         cmd_pipeline_selector_group_delete(tokens, n_tokens, out,
3204                                 out_size, obj);
3205                         return;
3206                 }
3207
3208                 if ((n_tokens >= 7) &&
3209                         (strcmp(tokens[2], "selector") == 0) &&
3210                         (strcmp(tokens[4], "group") == 0) &&
3211                         (strcmp(tokens[5], "member") == 0) &&
3212                         (strcmp(tokens[6], "add") == 0)) {
3213                         cmd_pipeline_selector_group_member_add(tokens, n_tokens, out,
3214                                 out_size, obj);
3215                         return;
3216                 }
3217
3218                 if ((n_tokens >= 7) &&
3219                         (strcmp(tokens[2], "selector") == 0) &&
3220                         (strcmp(tokens[4], "group") == 0) &&
3221                         (strcmp(tokens[5], "member") == 0) &&
3222                         (strcmp(tokens[6], "delete") == 0)) {
3223                         cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out,
3224                                 out_size, obj);
3225                         return;
3226                 }
3227
3228                 if ((n_tokens >= 5) &&
3229                         (strcmp(tokens[2], "selector") == 0) &&
3230                         (strcmp(tokens[4], "show") == 0)) {
3231                         cmd_pipeline_selector_show(tokens, n_tokens, out,
3232                                 out_size, obj);
3233                         return;
3234                 }
3235
3236                 if ((n_tokens >= 5) &&
3237                         (strcmp(tokens[2], "learner") == 0) &&
3238                         (strcmp(tokens[4], "default") == 0)) {
3239                         cmd_pipeline_learner_default(tokens, n_tokens, out,
3240                                 out_size, obj);
3241                         return;
3242                 }
3243
3244                 if ((n_tokens >= 3) &&
3245                         (strcmp(tokens[2], "commit") == 0)) {
3246                         cmd_pipeline_commit(tokens, n_tokens, out,
3247                                 out_size, obj);
3248                         return;
3249                 }
3250
3251                 if ((n_tokens >= 3) &&
3252                         (strcmp(tokens[2], "abort") == 0)) {
3253                         cmd_pipeline_abort(tokens, n_tokens, out,
3254                                 out_size, obj);
3255                         return;
3256                 }
3257
3258                 if ((n_tokens >= 3) &&
3259                         (strcmp(tokens[2], "regrd") == 0)) {
3260                         cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj);
3261                         return;
3262                 }
3263
3264                 if ((n_tokens >= 3) &&
3265                         (strcmp(tokens[2], "regwr") == 0)) {
3266                         cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj);
3267                         return;
3268                 }
3269
3270                 if ((n_tokens >= 6) &&
3271                         (strcmp(tokens[2], "meter") == 0) &&
3272                         (strcmp(tokens[3], "profile") == 0) &&
3273                         (strcmp(tokens[5], "add") == 0)) {
3274                         cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj);
3275                         return;
3276                 }
3277
3278                 if ((n_tokens >= 6) &&
3279                         (strcmp(tokens[2], "meter") == 0) &&
3280                         (strcmp(tokens[3], "profile") == 0) &&
3281                         (strcmp(tokens[5], "delete") == 0)) {
3282                         cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj);
3283                         return;
3284                 }
3285
3286                 if ((n_tokens >= 9) &&
3287                         (strcmp(tokens[2], "meter") == 0) &&
3288                         (strcmp(tokens[8], "reset") == 0)) {
3289                         cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj);
3290                         return;
3291                 }
3292
3293                 if ((n_tokens >= 9) &&
3294                         (strcmp(tokens[2], "meter") == 0) &&
3295                         (strcmp(tokens[8], "set") == 0)) {
3296                         cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj);
3297                         return;
3298                 }
3299
3300                 if ((n_tokens >= 9) &&
3301                         (strcmp(tokens[2], "meter") == 0) &&
3302                         (strcmp(tokens[8], "stats") == 0)) {
3303                         cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj);
3304                         return;
3305                 }
3306
3307                 if ((n_tokens >= 3) &&
3308                         (strcmp(tokens[2], "stats") == 0)) {
3309                         cmd_pipeline_stats(tokens, n_tokens, out, out_size,
3310                                 obj);
3311                         return;
3312                 }
3313         }
3314
3315         if (strcmp(tokens[0], "thread") == 0) {
3316                 if ((n_tokens >= 5) &&
3317                         (strcmp(tokens[4], "enable") == 0)) {
3318                         cmd_thread_pipeline_enable(tokens, n_tokens,
3319                                 out, out_size, obj);
3320                         return;
3321                 }
3322
3323                 if ((n_tokens >= 5) &&
3324                         (strcmp(tokens[4], "disable") == 0)) {
3325                         cmd_thread_pipeline_disable(tokens, n_tokens,
3326                                 out, out_size, obj);
3327                         return;
3328                 }
3329         }
3330
3331         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
3332 }
3333
3334 int
3335 cli_script_process(const char *file_name,
3336         size_t msg_in_len_max,
3337         size_t msg_out_len_max,
3338         void *obj)
3339 {
3340         char *msg_in = NULL, *msg_out = NULL;
3341         FILE *f = NULL;
3342
3343         /* Check input arguments */
3344         if ((file_name == NULL) ||
3345                 (strlen(file_name) == 0) ||
3346                 (msg_in_len_max == 0) ||
3347                 (msg_out_len_max == 0))
3348                 return -EINVAL;
3349
3350         msg_in = malloc(msg_in_len_max + 1);
3351         msg_out = malloc(msg_out_len_max + 1);
3352         if ((msg_in == NULL) ||
3353                 (msg_out == NULL)) {
3354                 free(msg_out);
3355                 free(msg_in);
3356                 return -ENOMEM;
3357         }
3358
3359         /* Open input file */
3360         f = fopen(file_name, "r");
3361         if (f == NULL) {
3362                 free(msg_out);
3363                 free(msg_in);
3364                 return -EIO;
3365         }
3366
3367         /* Read file */
3368         for ( ; ; ) {
3369                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
3370                         break;
3371
3372                 printf("%s", msg_in);
3373                 msg_out[0] = 0;
3374
3375                 cli_process(msg_in,
3376                         msg_out,
3377                         msg_out_len_max,
3378                         obj);
3379
3380                 if (strlen(msg_out))
3381                         printf("%s", msg_out);
3382         }
3383
3384         /* Close file */
3385         fclose(f);
3386         free(msg_out);
3387         free(msg_in);
3388         return 0;
3389 }