b9e1eea50e6a488498fa6223510a62b628832a2e
[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>\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 + 3) {
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                 t0 += 3;
702
703                 status = rte_swx_pipeline_port_in_config(p->p,
704                         port_id,
705                         "source",
706                         &params);
707         } else if (strcmp(tokens[t0], "tap") == 0) {
708                 struct rte_swx_port_fd_reader_params params;
709                 struct tap *tap;
710                 struct mempool *mp;
711
712                 if (n_tokens < t0 + 8) {
713                         snprintf(out, out_size, MSG_ARG_MISMATCH,
714                                 "pipeline port in tap");
715                         return;
716                 }
717
718                 tap = tap_find(obj, tokens[t0 + 1]);
719                 if (!tap) {
720                         snprintf(out, out_size, MSG_ARG_INVALID,
721                                 "tap_name");
722                         return;
723                 }
724                 params.fd = tap->fd;
725
726                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
727                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
728                                 "mempool");
729                         return;
730                 }
731
732                 mp = mempool_find(obj, tokens[t0 + 3]);
733                 if (!mp) {
734                         snprintf(out, out_size, MSG_ARG_INVALID,
735                                 "mempool_name");
736                         return;
737                 }
738                 params.mempool = mp->m;
739
740                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
741                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
742                                 "mtu");
743                         return;
744                 }
745
746                 if (parser_read_uint32(&params.mtu, tokens[t0 + 5]) != 0) {
747                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
748                         return;
749                 }
750
751                 if (strcmp(tokens[t0 + 6], "bsz") != 0) {
752                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
753                         return;
754                 }
755
756                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 7])) {
757                         snprintf(out, out_size, MSG_ARG_INVALID,
758                                 "burst_size");
759                         return;
760                 }
761
762                 t0 += 8;
763
764                 status = rte_swx_pipeline_port_in_config(p->p,
765                         port_id,
766                         "fd",
767                         &params);
768
769         } else {
770                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
771                 return;
772         }
773
774         if (status) {
775                 snprintf(out, out_size, "port in error.");
776                 return;
777         }
778
779         if (n_tokens != t0) {
780                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
781                 return;
782         }
783 }
784
785 static const char cmd_pipeline_port_out_help[] =
786 "pipeline <pipeline_name> port out <port_id>\n"
787 "   link <link_name> txq <txq_id> bsz <burst_size>\n"
788 "   ring <ring_name> bsz <burst_size>\n"
789 "   | sink <file_name> | none\n"
790 "   | tap <tap_name> bsz <burst_size>\n";
791
792 static void
793 cmd_pipeline_port_out(char **tokens,
794         uint32_t n_tokens,
795         char *out,
796         size_t out_size,
797         void *obj)
798 {
799         struct pipeline *p;
800         int status;
801         uint32_t port_id = 0, t0;
802
803         if (n_tokens < 6) {
804                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
805                 return;
806         }
807
808         p = pipeline_find(obj, tokens[1]);
809         if (!p || p->ctl) {
810                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
811                 return;
812         }
813
814         if (strcmp(tokens[2], "port") != 0) {
815                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
816                 return;
817         }
818
819         if (strcmp(tokens[3], "out") != 0) {
820                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
821                 return;
822         }
823
824         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
825                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
826                 return;
827         }
828
829         t0 = 5;
830
831         if (strcmp(tokens[t0], "link") == 0) {
832                 struct rte_swx_port_ethdev_writer_params params;
833                 struct link *link;
834
835                 if (n_tokens < t0 + 6) {
836                         snprintf(out, out_size, MSG_ARG_MISMATCH,
837                                 "pipeline port out link");
838                         return;
839                 }
840
841                 link = link_find(obj, tokens[t0 + 1]);
842                 if (!link) {
843                         snprintf(out, out_size, MSG_ARG_INVALID,
844                                 "link_name");
845                         return;
846                 }
847                 params.dev_name = link->dev_name;
848
849                 if (strcmp(tokens[t0 + 2], "txq") != 0) {
850                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
851                         return;
852                 }
853
854                 if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
855                         snprintf(out, out_size, MSG_ARG_INVALID,
856                                 "queue_id");
857                         return;
858                 }
859
860                 if (strcmp(tokens[t0 + 4], "bsz") != 0) {
861                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
862                         return;
863                 }
864
865                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
866                         snprintf(out, out_size, MSG_ARG_INVALID,
867                                 "burst_size");
868                         return;
869                 }
870
871                 t0 += 6;
872
873                 status = rte_swx_pipeline_port_out_config(p->p,
874                         port_id,
875                         "ethdev",
876                         &params);
877         } else if (strcmp(tokens[t0], "ring") == 0) {
878                 struct rte_swx_port_ring_writer_params params;
879                 struct ring *ring;
880
881                 if (n_tokens < t0 + 4) {
882                         snprintf(out, out_size, MSG_ARG_MISMATCH,
883                                 "pipeline port out link");
884                         return;
885                 }
886
887                 ring = ring_find(obj, tokens[t0 + 1]);
888                 if (!ring) {
889                         snprintf(out, out_size, MSG_ARG_INVALID,
890                                 "ring_name");
891                         return;
892                 }
893                 params.name = ring->name;
894
895                 if (strcmp(tokens[t0 + 2], "bsz") != 0) {
896                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
897                         return;
898                 }
899
900                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
901                         snprintf(out, out_size, MSG_ARG_INVALID,
902                                 "burst_size");
903                         return;
904                 }
905
906                 t0 += 4;
907
908                 status = rte_swx_pipeline_port_out_config(p->p,
909                         port_id,
910                         "ring",
911                         &params);
912         } else if (strcmp(tokens[t0], "sink") == 0) {
913                 struct rte_swx_port_sink_params params;
914
915                 params.file_name = strcmp(tokens[t0 + 1], "none") ?
916                         tokens[t0 + 1] : NULL;
917
918                 t0 += 2;
919
920                 status = rte_swx_pipeline_port_out_config(p->p,
921                         port_id,
922                         "sink",
923                         &params);
924         } else if (strcmp(tokens[t0], "tap") == 0) {
925                 struct rte_swx_port_fd_writer_params params;
926                 struct tap *tap;
927
928                 if (n_tokens < t0 + 4) {
929                         snprintf(out, out_size, MSG_ARG_MISMATCH,
930                                 "pipeline port out tap");
931                         return;
932                 }
933
934                 tap = tap_find(obj, tokens[t0 + 1]);
935                 if (!tap) {
936                         snprintf(out, out_size, MSG_ARG_INVALID,
937                                 "tap_name");
938                         return;
939                 }
940                 params.fd = tap->fd;
941
942                 if (strcmp(tokens[t0 + 2], "bsz") != 0) {
943                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
944                         return;
945                 }
946
947                 if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
948                         snprintf(out, out_size, MSG_ARG_INVALID,
949                                 "burst_size");
950                         return;
951                 }
952
953                 t0 += 4;
954
955                 status = rte_swx_pipeline_port_out_config(p->p,
956                         port_id,
957                         "fd",
958                         &params);
959         } else {
960                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
961                 return;
962         }
963
964         if (status) {
965                 snprintf(out, out_size, "port out error.");
966                 return;
967         }
968
969         if (n_tokens != t0) {
970                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
971                 return;
972         }
973 }
974
975 static const char cmd_pipeline_build_help[] =
976 "pipeline <pipeline_name> build <spec_file>\n";
977
978 static void
979 cmd_pipeline_build(char **tokens,
980         uint32_t n_tokens,
981         char *out,
982         size_t out_size,
983         void *obj)
984 {
985         struct pipeline *p = NULL;
986         FILE *spec = NULL;
987         uint32_t err_line;
988         const char *err_msg;
989         int status;
990
991         if (n_tokens != 4) {
992                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
993                 return;
994         }
995
996         p = pipeline_find(obj, tokens[1]);
997         if (!p || p->ctl) {
998                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
999                 return;
1000         }
1001
1002         spec = fopen(tokens[3], "r");
1003         if (!spec) {
1004                 snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
1005                 return;
1006         }
1007
1008         status = rte_swx_pipeline_build_from_spec(p->p,
1009                 spec,
1010                 &err_line,
1011                 &err_msg);
1012         fclose(spec);
1013         if (status) {
1014                 snprintf(out, out_size, "Error %d at line %u: %s\n.",
1015                         status, err_line, err_msg);
1016                 return;
1017         }
1018
1019         p->ctl = rte_swx_ctl_pipeline_create(p->p);
1020         if (!p->ctl) {
1021                 snprintf(out, out_size, "Pipeline control create failed.");
1022                 rte_swx_pipeline_free(p->p);
1023                 return;
1024         }
1025 }
1026
1027 static void
1028 table_entry_free(struct rte_swx_table_entry *entry)
1029 {
1030         if (!entry)
1031                 return;
1032
1033         free(entry->key);
1034         free(entry->key_mask);
1035         free(entry->action_data);
1036         free(entry);
1037 }
1038
1039 #ifndef MAX_LINE_SIZE
1040 #define MAX_LINE_SIZE 2048
1041 #endif
1042
1043 static int
1044 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p,
1045                            const char *table_name,
1046                            FILE *file,
1047                            uint32_t *file_line_number)
1048 {
1049         char *line = NULL;
1050         uint32_t line_id = 0;
1051         int status = 0;
1052
1053         /* Buffer allocation. */
1054         line = malloc(MAX_LINE_SIZE);
1055         if (!line)
1056                 return -ENOMEM;
1057
1058         /* File read. */
1059         for (line_id = 1; ; line_id++) {
1060                 struct rte_swx_table_entry *entry;
1061                 int is_blank_or_comment;
1062
1063                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1064                         break;
1065
1066                 entry = rte_swx_ctl_pipeline_table_entry_read(p,
1067                                                               table_name,
1068                                                               line,
1069                                                               &is_blank_or_comment);
1070                 if (!entry) {
1071                         if (is_blank_or_comment)
1072                                 continue;
1073
1074                         status = -EINVAL;
1075                         goto error;
1076                 }
1077
1078                 status = rte_swx_ctl_pipeline_table_entry_add(p,
1079                                                               table_name,
1080                                                               entry);
1081                 table_entry_free(entry);
1082                 if (status)
1083                         goto error;
1084         }
1085
1086 error:
1087         free(line);
1088         *file_line_number = line_id;
1089         return status;
1090 }
1091
1092 static const char cmd_pipeline_table_add_help[] =
1093 "pipeline <pipeline_name> table <table_name> add <file_name>\n";
1094
1095 static void
1096 cmd_pipeline_table_add(char **tokens,
1097                        uint32_t n_tokens,
1098                        char *out,
1099                        size_t out_size,
1100                        void *obj)
1101 {
1102         struct pipeline *p;
1103         char *pipeline_name, *table_name, *file_name;
1104         FILE *file = NULL;
1105         uint32_t file_line_number = 0;
1106         int status;
1107
1108         if (n_tokens != 6) {
1109                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1110                 return;
1111         }
1112
1113         pipeline_name = tokens[1];
1114         p = pipeline_find(obj, pipeline_name);
1115         if (!p || !p->ctl) {
1116                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1117                 return;
1118         }
1119
1120         table_name = tokens[3];
1121
1122         file_name = tokens[5];
1123         file = fopen(file_name, "r");
1124         if (!file) {
1125                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1126                 return;
1127         }
1128
1129         status = pipeline_table_entries_add(p->ctl,
1130                                             table_name,
1131                                             file,
1132                                             &file_line_number);
1133         if (status)
1134                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1135                          file_name,
1136                          file_line_number);
1137
1138         fclose(file);
1139 }
1140
1141 static int
1142 pipeline_table_entries_delete(struct rte_swx_ctl_pipeline *p,
1143                               const char *table_name,
1144                               FILE *file,
1145                               uint32_t *file_line_number)
1146 {
1147         char *line = NULL;
1148         uint32_t line_id = 0;
1149         int status = 0;
1150
1151         /* Buffer allocation. */
1152         line = malloc(MAX_LINE_SIZE);
1153         if (!line)
1154                 return -ENOMEM;
1155
1156         /* File read. */
1157         for (line_id = 1; ; line_id++) {
1158                 struct rte_swx_table_entry *entry;
1159                 int is_blank_or_comment;
1160
1161                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1162                         break;
1163
1164                 entry = rte_swx_ctl_pipeline_table_entry_read(p,
1165                                                               table_name,
1166                                                               line,
1167                                                               &is_blank_or_comment);
1168                 if (!entry) {
1169                         if (is_blank_or_comment)
1170                                 continue;
1171
1172                         status = -EINVAL;
1173                         goto error;
1174                 }
1175
1176                 status = rte_swx_ctl_pipeline_table_entry_delete(p,
1177                                                                  table_name,
1178                                                                  entry);
1179                 table_entry_free(entry);
1180                 if (status)
1181                         goto error;
1182         }
1183
1184 error:
1185         *file_line_number = line_id;
1186         free(line);
1187         return status;
1188 }
1189
1190 static const char cmd_pipeline_table_delete_help[] =
1191 "pipeline <pipeline_name> table <table_name> delete <file_name>\n";
1192
1193 static void
1194 cmd_pipeline_table_delete(char **tokens,
1195                           uint32_t n_tokens,
1196                           char *out,
1197                           size_t out_size,
1198                           void *obj)
1199 {
1200         struct pipeline *p;
1201         char *pipeline_name, *table_name, *file_name;
1202         FILE *file = NULL;
1203         uint32_t file_line_number = 0;
1204         int status;
1205
1206         if (n_tokens != 6) {
1207                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1208                 return;
1209         }
1210
1211         pipeline_name = tokens[1];
1212         p = pipeline_find(obj, pipeline_name);
1213         if (!p || !p->ctl) {
1214                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1215                 return;
1216         }
1217
1218         table_name = tokens[3];
1219
1220         file_name = tokens[5];
1221         file = fopen(file_name, "r");
1222         if (!file) {
1223                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1224                 return;
1225         }
1226
1227         status = pipeline_table_entries_delete(p->ctl,
1228                                                table_name,
1229                                                file,
1230                                                &file_line_number);
1231         if (status)
1232                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1233                          file_name,
1234                          file_line_number);
1235
1236         fclose(file);
1237 }
1238
1239 static int
1240 pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *p,
1241                                  const char *table_name,
1242                                  FILE *file,
1243                                  uint32_t *file_line_number)
1244 {
1245         char *line = NULL;
1246         uint32_t line_id = 0;
1247         int status = 0;
1248
1249         /* Buffer allocation. */
1250         line = malloc(MAX_LINE_SIZE);
1251         if (!line)
1252                 return -ENOMEM;
1253
1254         /* File read. */
1255         for (line_id = 1; ; line_id++) {
1256                 struct rte_swx_table_entry *entry;
1257                 int is_blank_or_comment;
1258
1259                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1260                         break;
1261
1262                 entry = rte_swx_ctl_pipeline_table_entry_read(p,
1263                                                               table_name,
1264                                                               line,
1265                                                               &is_blank_or_comment);
1266                 if (!entry) {
1267                         if (is_blank_or_comment)
1268                                 continue;
1269
1270                         status = -EINVAL;
1271                         goto error;
1272                 }
1273
1274                 status = rte_swx_ctl_pipeline_table_default_entry_add(p,
1275                                                                       table_name,
1276                                                                       entry);
1277                 table_entry_free(entry);
1278                 if (status)
1279                         goto error;
1280         }
1281
1282 error:
1283         *file_line_number = line_id;
1284         free(line);
1285         return status;
1286 }
1287
1288 static const char cmd_pipeline_table_default_help[] =
1289 "pipeline <pipeline_name> table <table_name> default <file_name>\n";
1290
1291 static void
1292 cmd_pipeline_table_default(char **tokens,
1293                            uint32_t n_tokens,
1294                            char *out,
1295                            size_t out_size,
1296                            void *obj)
1297 {
1298         struct pipeline *p;
1299         char *pipeline_name, *table_name, *file_name;
1300         FILE *file = NULL;
1301         uint32_t file_line_number = 0;
1302         int status;
1303
1304         if (n_tokens != 6) {
1305                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1306                 return;
1307         }
1308
1309         pipeline_name = tokens[1];
1310         p = pipeline_find(obj, pipeline_name);
1311         if (!p || !p->ctl) {
1312                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1313                 return;
1314         }
1315
1316         table_name = tokens[3];
1317
1318         file_name = tokens[5];
1319         file = fopen(file_name, "r");
1320         if (!file) {
1321                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1322                 return;
1323         }
1324
1325         status = pipeline_table_default_entry_add(p->ctl,
1326                                                   table_name,
1327                                                   file,
1328                                                   &file_line_number);
1329         if (status)
1330                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1331                          file_name,
1332                          file_line_number);
1333
1334         fclose(file);
1335 }
1336
1337 static const char cmd_pipeline_table_show_help[] =
1338 "pipeline <pipeline_name> table <table_name> show\n";
1339
1340 static void
1341 cmd_pipeline_table_show(char **tokens,
1342         uint32_t n_tokens,
1343         char *out,
1344         size_t out_size,
1345         void *obj)
1346 {
1347         struct pipeline *p;
1348         char *pipeline_name, *table_name;
1349         int status;
1350
1351         if (n_tokens != 5) {
1352                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1353                 return;
1354         }
1355
1356         pipeline_name = tokens[1];
1357         p = pipeline_find(obj, pipeline_name);
1358         if (!p || !p->ctl) {
1359                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1360                 return;
1361         }
1362
1363         table_name = tokens[3];
1364         status = rte_swx_ctl_pipeline_table_fprintf(stdout, p->ctl, table_name);
1365         if (status)
1366                 snprintf(out, out_size, MSG_ARG_INVALID, "table_name");
1367 }
1368
1369 static const char cmd_pipeline_selector_group_add_help[] =
1370 "pipeline <pipeline_name> selector <selector_name> group add\n";
1371
1372 static void
1373 cmd_pipeline_selector_group_add(char **tokens,
1374         uint32_t n_tokens,
1375         char *out,
1376         size_t out_size,
1377         void *obj)
1378 {
1379         struct pipeline *p;
1380         char *pipeline_name, *selector_name;
1381         uint32_t group_id;
1382         int status;
1383
1384         if (n_tokens != 6) {
1385                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1386                 return;
1387         }
1388
1389         pipeline_name = tokens[1];
1390         p = pipeline_find(obj, pipeline_name);
1391         if (!p || !p->ctl) {
1392                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1393                 return;
1394         }
1395
1396         if (strcmp(tokens[2], "selector") != 0) {
1397                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1398                 return;
1399         }
1400
1401         selector_name = tokens[3];
1402
1403         if (strcmp(tokens[4], "group") ||
1404                 strcmp(tokens[5], "add")) {
1405                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group add");
1406                 return;
1407         }
1408
1409         status = rte_swx_ctl_pipeline_selector_group_add(p->ctl,
1410                 selector_name,
1411                 &group_id);
1412         if (status)
1413                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1414         else
1415                 snprintf(out, out_size, "Group ID: %u\n", group_id);
1416 }
1417
1418 static const char cmd_pipeline_selector_group_delete_help[] =
1419 "pipeline <pipeline_name> selector <selector_name> group delete <group_id>\n";
1420
1421 static void
1422 cmd_pipeline_selector_group_delete(char **tokens,
1423         uint32_t n_tokens,
1424         char *out,
1425         size_t out_size,
1426         void *obj)
1427 {
1428         struct pipeline *p;
1429         char *pipeline_name, *selector_name;
1430         uint32_t group_id;
1431         int status;
1432
1433         if (n_tokens != 7) {
1434                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1435                 return;
1436         }
1437
1438         pipeline_name = tokens[1];
1439         p = pipeline_find(obj, pipeline_name);
1440         if (!p || !p->ctl) {
1441                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1442                 return;
1443         }
1444
1445         if (strcmp(tokens[2], "selector") != 0) {
1446                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1447                 return;
1448         }
1449
1450         selector_name = tokens[3];
1451
1452         if (strcmp(tokens[4], "group") ||
1453                 strcmp(tokens[5], "delete")) {
1454                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group delete");
1455                 return;
1456         }
1457
1458         if (parser_read_uint32(&group_id, tokens[6]) != 0) {
1459                 snprintf(out, out_size, MSG_ARG_INVALID, "group_id");
1460                 return;
1461         }
1462
1463         status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl,
1464                 selector_name,
1465                 group_id);
1466         if (status)
1467                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1468 }
1469
1470 #define GROUP_MEMBER_INFO_TOKENS_MAX 6
1471
1472 static int
1473 token_is_comment(const char *token)
1474 {
1475         if ((token[0] == '#') ||
1476             (token[0] == ';') ||
1477             ((token[0] == '/') && (token[1] == '/')))
1478                 return 1; /* TRUE. */
1479
1480         return 0; /* FALSE. */
1481 }
1482
1483 static int
1484 pipeline_selector_group_member_read(const char *string,
1485                                       uint32_t *group_id,
1486                                       uint32_t *member_id,
1487                                       uint32_t *weight,
1488                                       int *is_blank_or_comment)
1489 {
1490         char *token_array[GROUP_MEMBER_INFO_TOKENS_MAX], **tokens;
1491         char *s0 = NULL, *s;
1492         uint32_t n_tokens = 0, group_id_val = 0, member_id_val = 0, weight_val = 0;
1493         int blank_or_comment = 0;
1494
1495         /* Check input arguments. */
1496         if (!string || !string[0])
1497                 goto error;
1498
1499         /* Memory allocation. */
1500         s0 = strdup(string);
1501         if (!s0)
1502                 goto error;
1503
1504         /* Parse the string into tokens. */
1505         for (s = s0; ; ) {
1506                 char *token;
1507
1508                 token = strtok_r(s, " \f\n\r\t\v", &s);
1509                 if (!token || token_is_comment(token))
1510                         break;
1511
1512                 if (n_tokens >= GROUP_MEMBER_INFO_TOKENS_MAX)
1513                         goto error;
1514
1515                 token_array[n_tokens] = token;
1516                 n_tokens++;
1517         }
1518
1519         if (!n_tokens) {
1520                 blank_or_comment = 1;
1521                 goto error;
1522         }
1523
1524         tokens = token_array;
1525
1526         if (n_tokens < 4 ||
1527                 strcmp(tokens[0], "group") ||
1528                 strcmp(tokens[2], "member"))
1529                 goto error;
1530
1531         /*
1532          * Group ID.
1533          */
1534         if (parser_read_uint32(&group_id_val, tokens[1]) != 0)
1535                 goto error;
1536         *group_id = group_id_val;
1537
1538         /*
1539          * Member ID.
1540          */
1541         if (parser_read_uint32(&member_id_val, tokens[3]) != 0)
1542                 goto error;
1543         *member_id = member_id_val;
1544
1545         tokens += 4;
1546         n_tokens -= 4;
1547
1548         /*
1549          * Weight.
1550          */
1551         if (n_tokens && !strcmp(tokens[0], "weight")) {
1552                 if (n_tokens < 2)
1553                         goto error;
1554
1555                 if (parser_read_uint32(&weight_val, tokens[1]) != 0)
1556                         goto error;
1557                 *weight = weight_val;
1558
1559                 tokens += 2;
1560                 n_tokens -= 2;
1561         }
1562
1563         if (n_tokens)
1564                 goto error;
1565
1566         free(s0);
1567         return 0;
1568
1569 error:
1570         free(s0);
1571         if (is_blank_or_comment)
1572                 *is_blank_or_comment = blank_or_comment;
1573         return -EINVAL;
1574 }
1575
1576 static int
1577 pipeline_selector_group_members_add(struct rte_swx_ctl_pipeline *p,
1578                            const char *selector_name,
1579                            FILE *file,
1580                            uint32_t *file_line_number)
1581 {
1582         char *line = NULL;
1583         uint32_t line_id = 0;
1584         int status = 0;
1585
1586         /* Buffer allocation. */
1587         line = malloc(MAX_LINE_SIZE);
1588         if (!line)
1589                 return -ENOMEM;
1590
1591         /* File read. */
1592         for (line_id = 1; ; line_id++) {
1593                 uint32_t group_id, member_id, weight;
1594                 int is_blank_or_comment;
1595
1596                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1597                         break;
1598
1599                 status = pipeline_selector_group_member_read(line,
1600                                                               &group_id,
1601                                                               &member_id,
1602                                                               &weight,
1603                                                               &is_blank_or_comment);
1604                 if (status) {
1605                         if (is_blank_or_comment)
1606                                 continue;
1607
1608                         goto error;
1609                 }
1610
1611                 status = rte_swx_ctl_pipeline_selector_group_member_add(p,
1612                         selector_name,
1613                         group_id,
1614                         member_id,
1615                         weight);
1616                 if (status)
1617                         goto error;
1618         }
1619
1620 error:
1621         free(line);
1622         *file_line_number = line_id;
1623         return status;
1624 }
1625
1626 static const char cmd_pipeline_selector_group_member_add_help[] =
1627 "pipeline <pipeline_name> selector <selector_name> group member add <file_name>";
1628
1629 static void
1630 cmd_pipeline_selector_group_member_add(char **tokens,
1631         uint32_t n_tokens,
1632         char *out,
1633         size_t out_size,
1634         void *obj)
1635 {
1636         struct pipeline *p;
1637         char *pipeline_name, *selector_name, *file_name;
1638         FILE *file = NULL;
1639         uint32_t file_line_number = 0;
1640         int status;
1641
1642         if (n_tokens != 8) {
1643                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1644                 return;
1645         }
1646
1647         pipeline_name = tokens[1];
1648         p = pipeline_find(obj, pipeline_name);
1649         if (!p || !p->ctl) {
1650                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1651                 return;
1652         }
1653
1654         if (strcmp(tokens[2], "selector") != 0) {
1655                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1656                 return;
1657         }
1658
1659         selector_name = tokens[3];
1660
1661         if (strcmp(tokens[4], "group") ||
1662                 strcmp(tokens[5], "member") ||
1663                 strcmp(tokens[6], "add")) {
1664                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member add");
1665                 return;
1666         }
1667
1668         file_name = tokens[7];
1669         file = fopen(file_name, "r");
1670         if (!file) {
1671                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1672                 return;
1673         }
1674
1675         status = pipeline_selector_group_members_add(p->ctl,
1676                                             selector_name,
1677                                             file,
1678                                             &file_line_number);
1679         if (status)
1680                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1681                          file_name,
1682                          file_line_number);
1683
1684         fclose(file);
1685 }
1686
1687 static int
1688 pipeline_selector_group_members_delete(struct rte_swx_ctl_pipeline *p,
1689                            const char *selector_name,
1690                            FILE *file,
1691                            uint32_t *file_line_number)
1692 {
1693         char *line = NULL;
1694         uint32_t line_id = 0;
1695         int status = 0;
1696
1697         /* Buffer allocation. */
1698         line = malloc(MAX_LINE_SIZE);
1699         if (!line)
1700                 return -ENOMEM;
1701
1702         /* File read. */
1703         for (line_id = 1; ; line_id++) {
1704                 uint32_t group_id, member_id, weight;
1705                 int is_blank_or_comment;
1706
1707                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1708                         break;
1709
1710                 status = pipeline_selector_group_member_read(line,
1711                                                               &group_id,
1712                                                               &member_id,
1713                                                               &weight,
1714                                                               &is_blank_or_comment);
1715                 if (status) {
1716                         if (is_blank_or_comment)
1717                                 continue;
1718
1719                         goto error;
1720                 }
1721
1722                 status = rte_swx_ctl_pipeline_selector_group_member_delete(p,
1723                         selector_name,
1724                         group_id,
1725                         member_id);
1726                 if (status)
1727                         goto error;
1728         }
1729
1730 error:
1731         free(line);
1732         *file_line_number = line_id;
1733         return status;
1734 }
1735
1736 static const char cmd_pipeline_selector_group_member_delete_help[] =
1737 "pipeline <pipeline_name> selector <selector_name> group member delete <file_name>";
1738
1739 static void
1740 cmd_pipeline_selector_group_member_delete(char **tokens,
1741         uint32_t n_tokens,
1742         char *out,
1743         size_t out_size,
1744         void *obj)
1745 {
1746         struct pipeline *p;
1747         char *pipeline_name, *selector_name, *file_name;
1748         FILE *file = NULL;
1749         uint32_t file_line_number = 0;
1750         int status;
1751
1752         if (n_tokens != 8) {
1753                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1754                 return;
1755         }
1756
1757         pipeline_name = tokens[1];
1758         p = pipeline_find(obj, pipeline_name);
1759         if (!p || !p->ctl) {
1760                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1761                 return;
1762         }
1763
1764         if (strcmp(tokens[2], "selector") != 0) {
1765                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1766                 return;
1767         }
1768
1769         selector_name = tokens[3];
1770
1771         if (strcmp(tokens[4], "group") ||
1772                 strcmp(tokens[5], "member") ||
1773                 strcmp(tokens[6], "delete")) {
1774                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member delete");
1775                 return;
1776         }
1777
1778         file_name = tokens[7];
1779         file = fopen(file_name, "r");
1780         if (!file) {
1781                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1782                 return;
1783         }
1784
1785         status = pipeline_selector_group_members_delete(p->ctl,
1786                                             selector_name,
1787                                             file,
1788                                             &file_line_number);
1789         if (status)
1790                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1791                          file_name,
1792                          file_line_number);
1793
1794         fclose(file);
1795 }
1796
1797 static const char cmd_pipeline_selector_show_help[] =
1798 "pipeline <pipeline_name> selector <selector_name> show\n";
1799
1800 static void
1801 cmd_pipeline_selector_show(char **tokens,
1802         uint32_t n_tokens,
1803         char *out,
1804         size_t out_size,
1805         void *obj)
1806 {
1807         struct pipeline *p;
1808         char *pipeline_name, *selector_name;
1809         int status;
1810
1811         if (n_tokens != 5) {
1812                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1813                 return;
1814         }
1815
1816         pipeline_name = tokens[1];
1817         p = pipeline_find(obj, pipeline_name);
1818         if (!p || !p->ctl) {
1819                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1820                 return;
1821         }
1822
1823         selector_name = tokens[3];
1824         status = rte_swx_ctl_pipeline_selector_fprintf(stdout,
1825                 p->ctl, selector_name);
1826         if (status)
1827                 snprintf(out, out_size, MSG_ARG_INVALID, "selector_name");
1828 }
1829
1830 static int
1831 pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *p,
1832                                    const char *learner_name,
1833                                    FILE *file,
1834                                    uint32_t *file_line_number)
1835 {
1836         char *line = NULL;
1837         uint32_t line_id = 0;
1838         int status = 0;
1839
1840         /* Buffer allocation. */
1841         line = malloc(MAX_LINE_SIZE);
1842         if (!line)
1843                 return -ENOMEM;
1844
1845         /* File read. */
1846         for (line_id = 1; ; line_id++) {
1847                 struct rte_swx_table_entry *entry;
1848                 int is_blank_or_comment;
1849
1850                 if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1851                         break;
1852
1853                 entry = rte_swx_ctl_pipeline_learner_default_entry_read(p,
1854                                                                         learner_name,
1855                                                                         line,
1856                                                                         &is_blank_or_comment);
1857                 if (!entry) {
1858                         if (is_blank_or_comment)
1859                                 continue;
1860
1861                         status = -EINVAL;
1862                         goto error;
1863                 }
1864
1865                 status = rte_swx_ctl_pipeline_learner_default_entry_add(p,
1866                                                                         learner_name,
1867                                                                         entry);
1868                 table_entry_free(entry);
1869                 if (status)
1870                         goto error;
1871         }
1872
1873 error:
1874         *file_line_number = line_id;
1875         free(line);
1876         return status;
1877 }
1878
1879 static const char cmd_pipeline_learner_default_help[] =
1880 "pipeline <pipeline_name> learner <learner_name> default <file_name>\n";
1881
1882 static void
1883 cmd_pipeline_learner_default(char **tokens,
1884                              uint32_t n_tokens,
1885                              char *out,
1886                              size_t out_size,
1887                              void *obj)
1888 {
1889         struct pipeline *p;
1890         char *pipeline_name, *learner_name, *file_name;
1891         FILE *file = NULL;
1892         uint32_t file_line_number = 0;
1893         int status;
1894
1895         if (n_tokens != 6) {
1896                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1897                 return;
1898         }
1899
1900         pipeline_name = tokens[1];
1901         p = pipeline_find(obj, pipeline_name);
1902         if (!p || !p->ctl) {
1903                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1904                 return;
1905         }
1906
1907         learner_name = tokens[3];
1908
1909         file_name = tokens[5];
1910         file = fopen(file_name, "r");
1911         if (!file) {
1912                 snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1913                 return;
1914         }
1915
1916         status = pipeline_learner_default_entry_add(p->ctl,
1917                                                     learner_name,
1918                                                     file,
1919                                                     &file_line_number);
1920         if (status)
1921                 snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1922                          file_name,
1923                          file_line_number);
1924
1925         fclose(file);
1926 }
1927
1928 static const char cmd_pipeline_commit_help[] =
1929 "pipeline <pipeline_name> commit\n";
1930
1931 static void
1932 cmd_pipeline_commit(char **tokens,
1933         uint32_t n_tokens,
1934         char *out,
1935         size_t out_size,
1936         void *obj)
1937 {
1938         struct pipeline *p;
1939         char *pipeline_name;
1940         int status;
1941
1942         if (n_tokens != 3) {
1943                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1944                 return;
1945         }
1946
1947         pipeline_name = tokens[1];
1948         p = pipeline_find(obj, pipeline_name);
1949         if (!p || !p->ctl) {
1950                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1951                 return;
1952         }
1953
1954         status = rte_swx_ctl_pipeline_commit(p->ctl, 1);
1955         if (status)
1956                 snprintf(out, out_size, "Commit failed. "
1957                         "Use \"commit\" to retry or \"abort\" to discard the pending work.\n");
1958 }
1959
1960 static const char cmd_pipeline_abort_help[] =
1961 "pipeline <pipeline_name> abort\n";
1962
1963 static void
1964 cmd_pipeline_abort(char **tokens,
1965         uint32_t n_tokens,
1966         char *out,
1967         size_t out_size,
1968         void *obj)
1969 {
1970         struct pipeline *p;
1971         char *pipeline_name;
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         rte_swx_ctl_pipeline_abort(p->ctl);
1986 }
1987
1988 static const char cmd_pipeline_regrd_help[] =
1989 "pipeline <pipeline_name> regrd <register_array_name> <index>\n";
1990
1991 static void
1992 cmd_pipeline_regrd(char **tokens,
1993         uint32_t n_tokens,
1994         char *out,
1995         size_t out_size,
1996         void *obj)
1997 {
1998         struct pipeline *p;
1999         const char *name;
2000         uint64_t value;
2001         uint32_t idx;
2002         int status;
2003
2004         if (n_tokens != 5) {
2005                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2006                 return;
2007         }
2008
2009         p = pipeline_find(obj, tokens[1]);
2010         if (!p || !p->ctl) {
2011                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2012                 return;
2013         }
2014
2015         if (strcmp(tokens[2], "regrd")) {
2016                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd");
2017                 return;
2018         }
2019
2020         name = tokens[3];
2021
2022         if (parser_read_uint32(&idx, tokens[4])) {
2023                 snprintf(out, out_size, MSG_ARG_INVALID, "index");
2024                 return;
2025         }
2026
2027         status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);
2028         if (status) {
2029                 snprintf(out, out_size, "Command failed.\n");
2030                 return;
2031         }
2032
2033         snprintf(out, out_size, "0x%" PRIx64 "\n", value);
2034 }
2035
2036 static const char cmd_pipeline_regwr_help[] =
2037 "pipeline <pipeline_name> regwr <register_array_name> <index> <value>\n";
2038
2039 static void
2040 cmd_pipeline_regwr(char **tokens,
2041         uint32_t n_tokens,
2042         char *out,
2043         size_t out_size,
2044         void *obj)
2045 {
2046         struct pipeline *p;
2047         const char *name;
2048         uint64_t value;
2049         uint32_t idx;
2050         int status;
2051
2052         if (n_tokens != 6) {
2053                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2054                 return;
2055         }
2056
2057         p = pipeline_find(obj, tokens[1]);
2058         if (!p || !p->ctl) {
2059                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2060                 return;
2061         }
2062
2063         if (strcmp(tokens[2], "regwr")) {
2064                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr");
2065                 return;
2066         }
2067
2068         name = tokens[3];
2069
2070         if (parser_read_uint32(&idx, tokens[4])) {
2071                 snprintf(out, out_size, MSG_ARG_INVALID, "index");
2072                 return;
2073         }
2074
2075         if (parser_read_uint64(&value, tokens[5])) {
2076                 snprintf(out, out_size, MSG_ARG_INVALID, "value");
2077                 return;
2078         }
2079
2080         status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);
2081         if (status) {
2082                 snprintf(out, out_size, "Command failed.\n");
2083                 return;
2084         }
2085 }
2086
2087 static const char cmd_pipeline_meter_profile_add_help[] =
2088 "pipeline <pipeline_name> meter profile <profile_name> add "
2089         "cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
2090
2091 static void
2092 cmd_pipeline_meter_profile_add(char **tokens,
2093         uint32_t n_tokens,
2094         char *out,
2095         size_t out_size,
2096         void *obj)
2097 {
2098         struct rte_meter_trtcm_params params;
2099         struct pipeline *p;
2100         const char *profile_name;
2101         int status;
2102
2103         if (n_tokens != 14) {
2104                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2105                 return;
2106         }
2107
2108         p = pipeline_find(obj, tokens[1]);
2109         if (!p || !p->ctl) {
2110                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2111                 return;
2112         }
2113
2114         if (strcmp(tokens[2], "meter")) {
2115                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2116                 return;
2117         }
2118
2119         if (strcmp(tokens[3], "profile")) {
2120                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
2121                 return;
2122         }
2123
2124         profile_name = tokens[4];
2125
2126         if (strcmp(tokens[5], "add")) {
2127                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
2128                 return;
2129         }
2130
2131         if (strcmp(tokens[6], "cir")) {
2132                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
2133                 return;
2134         }
2135
2136         if (parser_read_uint64(&params.cir, tokens[7])) {
2137                 snprintf(out, out_size, MSG_ARG_INVALID, "cir");
2138                 return;
2139         }
2140
2141         if (strcmp(tokens[8], "pir")) {
2142                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
2143                 return;
2144         }
2145
2146         if (parser_read_uint64(&params.pir, tokens[9])) {
2147                 snprintf(out, out_size, MSG_ARG_INVALID, "pir");
2148                 return;
2149         }
2150
2151         if (strcmp(tokens[10], "cbs")) {
2152                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
2153                 return;
2154         }
2155
2156         if (parser_read_uint64(&params.cbs, tokens[11])) {
2157                 snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
2158                 return;
2159         }
2160
2161         if (strcmp(tokens[12], "pbs")) {
2162                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
2163                 return;
2164         }
2165
2166         if (parser_read_uint64(&params.pbs, tokens[13])) {
2167                 snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
2168                 return;
2169         }
2170
2171         status = rte_swx_ctl_meter_profile_add(p->p, profile_name, &params);
2172         if (status) {
2173                 snprintf(out, out_size, "Command failed.\n");
2174                 return;
2175         }
2176 }
2177
2178 static const char cmd_pipeline_meter_profile_delete_help[] =
2179 "pipeline <pipeline_name> meter profile <profile_name> delete\n";
2180
2181 static void
2182 cmd_pipeline_meter_profile_delete(char **tokens,
2183         uint32_t n_tokens,
2184         char *out,
2185         size_t out_size,
2186         void *obj)
2187 {
2188         struct pipeline *p;
2189         const char *profile_name;
2190         int status;
2191
2192         if (n_tokens != 6) {
2193                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2194                 return;
2195         }
2196
2197         p = pipeline_find(obj, tokens[1]);
2198         if (!p || !p->ctl) {
2199                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2200                 return;
2201         }
2202
2203         if (strcmp(tokens[2], "meter")) {
2204                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2205                 return;
2206         }
2207
2208         if (strcmp(tokens[3], "profile")) {
2209                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
2210                 return;
2211         }
2212
2213         profile_name = tokens[4];
2214
2215         if (strcmp(tokens[5], "delete")) {
2216                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
2217                 return;
2218         }
2219
2220         status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
2221         if (status) {
2222                 snprintf(out, out_size, "Command failed.\n");
2223                 return;
2224         }
2225 }
2226
2227 static const char cmd_pipeline_meter_reset_help[] =
2228 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
2229         "reset\n";
2230
2231 static void
2232 cmd_pipeline_meter_reset(char **tokens,
2233         uint32_t n_tokens,
2234         char *out,
2235         size_t out_size,
2236         void *obj)
2237 {
2238         struct pipeline *p;
2239         const char *name;
2240         uint32_t idx0 = 0, idx1 = 0;
2241
2242         if (n_tokens != 9) {
2243                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2244                 return;
2245         }
2246
2247         p = pipeline_find(obj, tokens[1]);
2248         if (!p || !p->ctl) {
2249                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2250                 return;
2251         }
2252
2253         if (strcmp(tokens[2], "meter")) {
2254                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2255                 return;
2256         }
2257
2258         name = tokens[3];
2259
2260         if (strcmp(tokens[4], "from")) {
2261                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
2262                 return;
2263         }
2264
2265         if (parser_read_uint32(&idx0, tokens[5])) {
2266                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
2267                 return;
2268         }
2269
2270         if (strcmp(tokens[6], "to")) {
2271                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
2272                 return;
2273         }
2274
2275         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
2276                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
2277                 return;
2278         }
2279
2280         if (strcmp(tokens[8], "reset")) {
2281                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset");
2282                 return;
2283         }
2284
2285         for ( ; idx0 <= idx1; idx0++) {
2286                 int status;
2287
2288                 status = rte_swx_ctl_meter_reset(p->p, name, idx0);
2289                 if (status) {
2290                         snprintf(out, out_size, "Command failed for index %u.\n", idx0);
2291                         return;
2292                 }
2293         }
2294 }
2295
2296 static const char cmd_pipeline_meter_set_help[] =
2297 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
2298         "set profile <profile_name>\n";
2299
2300 static void
2301 cmd_pipeline_meter_set(char **tokens,
2302         uint32_t n_tokens,
2303         char *out,
2304         size_t out_size,
2305         void *obj)
2306 {
2307         struct pipeline *p;
2308         const char *name, *profile_name;
2309         uint32_t idx0 = 0, idx1 = 0;
2310
2311         if (n_tokens != 11) {
2312                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2313                 return;
2314         }
2315
2316         p = pipeline_find(obj, tokens[1]);
2317         if (!p || !p->ctl) {
2318                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2319                 return;
2320         }
2321
2322         if (strcmp(tokens[2], "meter")) {
2323                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2324                 return;
2325         }
2326
2327         name = tokens[3];
2328
2329         if (strcmp(tokens[4], "from")) {
2330                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
2331                 return;
2332         }
2333
2334         if (parser_read_uint32(&idx0, tokens[5])) {
2335                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
2336                 return;
2337         }
2338
2339         if (strcmp(tokens[6], "to")) {
2340                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
2341                 return;
2342         }
2343
2344         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
2345                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
2346                 return;
2347         }
2348
2349         if (strcmp(tokens[8], "set")) {
2350                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set");
2351                 return;
2352         }
2353
2354         if (strcmp(tokens[9], "profile")) {
2355                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
2356                 return;
2357         }
2358
2359         profile_name = tokens[10];
2360
2361         for ( ; idx0 <= idx1; idx0++) {
2362                 int status;
2363
2364                 status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
2365                 if (status) {
2366                         snprintf(out, out_size, "Command failed for index %u.\n", idx0);
2367                         return;
2368                 }
2369         }
2370 }
2371
2372 static const char cmd_pipeline_meter_stats_help[] =
2373 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
2374         "stats\n";
2375
2376 static void
2377 cmd_pipeline_meter_stats(char **tokens,
2378         uint32_t n_tokens,
2379         char *out,
2380         size_t out_size,
2381         void *obj)
2382 {
2383         struct rte_swx_ctl_meter_stats stats;
2384         struct pipeline *p;
2385         const char *name;
2386         uint32_t idx0 = 0, idx1 = 0;
2387
2388         if (n_tokens != 9) {
2389                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2390                 return;
2391         }
2392
2393         p = pipeline_find(obj, tokens[1]);
2394         if (!p || !p->ctl) {
2395                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2396                 return;
2397         }
2398
2399         if (strcmp(tokens[2], "meter")) {
2400                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2401                 return;
2402         }
2403
2404         name = tokens[3];
2405
2406         if (strcmp(tokens[4], "from")) {
2407                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
2408                 return;
2409         }
2410
2411         if (parser_read_uint32(&idx0, tokens[5])) {
2412                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
2413                 return;
2414         }
2415
2416         if (strcmp(tokens[6], "to")) {
2417                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
2418                 return;
2419         }
2420
2421         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
2422                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
2423                 return;
2424         }
2425
2426         if (strcmp(tokens[8], "stats")) {
2427                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2428                 return;
2429         }
2430
2431         /* Table header. */
2432         snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
2433                  "-------",
2434                  "----------------", "----------------", "----------------",
2435                  "----------------", "----------------", "----------------");
2436         out_size -= strlen(out);
2437         out += strlen(out);
2438
2439         snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n",
2440                  "METER #",
2441                  "GREEN (packets)", "YELLOW (packets)", "RED (packets)",
2442                  "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)");
2443         out_size -= strlen(out);
2444         out += strlen(out);
2445
2446         snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
2447                  "-------",
2448                  "----------------", "----------------", "----------------",
2449                  "----------------", "----------------", "----------------");
2450         out_size -= strlen(out);
2451         out += strlen(out);
2452
2453         /* Table rows. */
2454         for ( ; idx0 <= idx1; idx0++) {
2455                 int status;
2456
2457                 status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
2458                 if (status) {
2459                         snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
2460                         out_size -= strlen(out);
2461                         out += strlen(out);
2462                         return;
2463                 }
2464
2465                 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64
2466                          " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n",
2467                          idx0,
2468                          stats.n_pkts[RTE_COLOR_GREEN],
2469                          stats.n_pkts[RTE_COLOR_YELLOW],
2470                          stats.n_pkts[RTE_COLOR_RED],
2471                          stats.n_bytes[RTE_COLOR_GREEN],
2472                          stats.n_bytes[RTE_COLOR_YELLOW],
2473                          stats.n_bytes[RTE_COLOR_RED]);
2474                 out_size -= strlen(out);
2475                 out += strlen(out);
2476         }
2477 }
2478
2479 static const char cmd_pipeline_stats_help[] =
2480 "pipeline <pipeline_name> stats\n";
2481
2482 static void
2483 cmd_pipeline_stats(char **tokens,
2484         uint32_t n_tokens,
2485         char *out,
2486         size_t out_size,
2487         void *obj)
2488 {
2489         struct rte_swx_ctl_pipeline_info info;
2490         struct pipeline *p;
2491         uint32_t i;
2492         int status;
2493
2494         if (n_tokens != 3) {
2495                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2496                 return;
2497         }
2498
2499         p = pipeline_find(obj, tokens[1]);
2500         if (!p || !p->ctl) {
2501                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2502                 return;
2503         }
2504
2505         if (strcmp(tokens[2], "stats")) {
2506                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2507                 return;
2508         }
2509
2510         status = rte_swx_ctl_pipeline_info_get(p->p, &info);
2511         if (status) {
2512                 snprintf(out, out_size, "Pipeline info get error.");
2513                 return;
2514         }
2515
2516         snprintf(out, out_size, "Input ports:\n");
2517         out_size -= strlen(out);
2518         out += strlen(out);
2519
2520         for (i = 0; i < info.n_ports_in; i++) {
2521                 struct rte_swx_port_in_stats stats;
2522
2523                 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
2524
2525                 snprintf(out, out_size, "\tPort %u:"
2526                         " packets %" PRIu64
2527                         " bytes %" PRIu64
2528                         " empty %" PRIu64 "\n",
2529                         i, stats.n_pkts, stats.n_bytes, stats.n_empty);
2530                 out_size -= strlen(out);
2531                 out += strlen(out);
2532         }
2533
2534         snprintf(out, out_size, "\nOutput ports:\n");
2535         out_size -= strlen(out);
2536         out += strlen(out);
2537
2538         for (i = 0; i < info.n_ports_out; i++) {
2539                 struct rte_swx_port_out_stats stats;
2540
2541                 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
2542
2543                 snprintf(out, out_size, "\tPort %u:"
2544                         " packets %" PRIu64
2545                         " bytes %" PRIu64 "\n",
2546                         i, stats.n_pkts, stats.n_bytes);
2547                 out_size -= strlen(out);
2548                 out += strlen(out);
2549         }
2550
2551         snprintf(out, out_size, "\nTables:\n");
2552         out_size -= strlen(out);
2553         out += strlen(out);
2554
2555         for (i = 0; i < info.n_tables; i++) {
2556                 struct rte_swx_ctl_table_info table_info;
2557                 uint64_t n_pkts_action[info.n_actions];
2558                 struct rte_swx_table_stats stats = {
2559                         .n_pkts_hit = 0,
2560                         .n_pkts_miss = 0,
2561                         .n_pkts_action = n_pkts_action,
2562                 };
2563                 uint32_t j;
2564
2565                 status = rte_swx_ctl_table_info_get(p->p, i, &table_info);
2566                 if (status) {
2567                         snprintf(out, out_size, "Table info get error.");
2568                         return;
2569                 }
2570
2571                 status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats);
2572                 if (status) {
2573                         snprintf(out, out_size, "Table stats read error.");
2574                         return;
2575                 }
2576
2577                 snprintf(out, out_size, "\tTable %s:\n"
2578                         "\t\tHit (packets): %" PRIu64 "\n"
2579                         "\t\tMiss (packets): %" PRIu64 "\n",
2580                         table_info.name,
2581                         stats.n_pkts_hit,
2582                         stats.n_pkts_miss);
2583                 out_size -= strlen(out);
2584                 out += strlen(out);
2585
2586                 for (j = 0; j < info.n_actions; j++) {
2587                         struct rte_swx_ctl_action_info action_info;
2588
2589                         status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
2590                         if (status) {
2591                                 snprintf(out, out_size, "Action info get error.");
2592                                 return;
2593                         }
2594
2595                         snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n",
2596                                 action_info.name,
2597                                 stats.n_pkts_action[j]);
2598                         out_size -= strlen(out);
2599                         out += strlen(out);
2600                 }
2601         }
2602
2603         snprintf(out, out_size, "\nLearner tables:\n");
2604         out_size -= strlen(out);
2605         out += strlen(out);
2606
2607         for (i = 0; i < info.n_learners; i++) {
2608                 struct rte_swx_ctl_learner_info learner_info;
2609                 uint64_t n_pkts_action[info.n_actions];
2610                 struct rte_swx_learner_stats stats = {
2611                         .n_pkts_hit = 0,
2612                         .n_pkts_miss = 0,
2613                         .n_pkts_action = n_pkts_action,
2614                 };
2615                 uint32_t j;
2616
2617                 status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info);
2618                 if (status) {
2619                         snprintf(out, out_size, "Learner table info get error.");
2620                         return;
2621                 }
2622
2623                 status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats);
2624                 if (status) {
2625                         snprintf(out, out_size, "Learner table stats read error.");
2626                         return;
2627                 }
2628
2629                 snprintf(out, out_size, "\tLearner table %s:\n"
2630                         "\t\tHit (packets): %" PRIu64 "\n"
2631                         "\t\tMiss (packets): %" PRIu64 "\n"
2632                         "\t\tLearn OK (packets): %" PRIu64 "\n"
2633                         "\t\tLearn error (packets): %" PRIu64 "\n"
2634                         "\t\tForget (packets): %" PRIu64 "\n",
2635                         learner_info.name,
2636                         stats.n_pkts_hit,
2637                         stats.n_pkts_miss,
2638                         stats.n_pkts_learn_ok,
2639                         stats.n_pkts_learn_err,
2640                         stats.n_pkts_forget);
2641                 out_size -= strlen(out);
2642                 out += strlen(out);
2643
2644                 for (j = 0; j < info.n_actions; j++) {
2645                         struct rte_swx_ctl_action_info action_info;
2646
2647                         status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
2648                         if (status) {
2649                                 snprintf(out, out_size, "Action info get error.");
2650                                 return;
2651                         }
2652
2653                         snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n",
2654                                 action_info.name,
2655                                 stats.n_pkts_action[j]);
2656                         out_size -= strlen(out);
2657                         out += strlen(out);
2658                 }
2659         }
2660 }
2661
2662 static const char cmd_thread_pipeline_enable_help[] =
2663 "thread <thread_id> pipeline <pipeline_name> enable\n";
2664
2665 static void
2666 cmd_thread_pipeline_enable(char **tokens,
2667         uint32_t n_tokens,
2668         char *out,
2669         size_t out_size,
2670         void *obj)
2671 {
2672         char *pipeline_name;
2673         struct pipeline *p;
2674         uint32_t thread_id;
2675         int status;
2676
2677         if (n_tokens != 5) {
2678                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2679                 return;
2680         }
2681
2682         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2683                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2684                 return;
2685         }
2686
2687         if (strcmp(tokens[2], "pipeline") != 0) {
2688                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2689                 return;
2690         }
2691
2692         pipeline_name = tokens[3];
2693         p = pipeline_find(obj, pipeline_name);
2694         if (!p || !p->ctl) {
2695                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2696                 return;
2697         }
2698
2699         if (strcmp(tokens[4], "enable") != 0) {
2700                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2701                 return;
2702         }
2703
2704         status = thread_pipeline_enable(thread_id, obj, pipeline_name);
2705         if (status) {
2706                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
2707                 return;
2708         }
2709 }
2710
2711 static const char cmd_thread_pipeline_disable_help[] =
2712 "thread <thread_id> pipeline <pipeline_name> disable\n";
2713
2714 static void
2715 cmd_thread_pipeline_disable(char **tokens,
2716         uint32_t n_tokens,
2717         char *out,
2718         size_t out_size,
2719         void *obj)
2720 {
2721         struct pipeline *p;
2722         char *pipeline_name;
2723         uint32_t thread_id;
2724         int status;
2725
2726         if (n_tokens != 5) {
2727                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2728                 return;
2729         }
2730
2731         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2732                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2733                 return;
2734         }
2735
2736         if (strcmp(tokens[2], "pipeline") != 0) {
2737                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2738                 return;
2739         }
2740
2741         pipeline_name = tokens[3];
2742         p = pipeline_find(obj, pipeline_name);
2743         if (!p || !p->ctl) {
2744                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2745                 return;
2746         }
2747
2748         if (strcmp(tokens[4], "disable") != 0) {
2749                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2750                 return;
2751         }
2752
2753         status = thread_pipeline_disable(thread_id, obj, pipeline_name);
2754         if (status) {
2755                 snprintf(out, out_size, MSG_CMD_FAIL,
2756                         "thread pipeline disable");
2757                 return;
2758         }
2759 }
2760
2761 static void
2762 cmd_help(char **tokens,
2763          uint32_t n_tokens,
2764          char *out,
2765          size_t out_size,
2766          void *arg __rte_unused)
2767 {
2768         tokens++;
2769         n_tokens--;
2770
2771         if (n_tokens == 0) {
2772                 snprintf(out, out_size,
2773                         "Type 'help <command>' for command details.\n\n"
2774                         "List of commands:\n"
2775                         "\tmempool\n"
2776                         "\tlink\n"
2777                         "\ttap\n"
2778                         "\tpipeline create\n"
2779                         "\tpipeline port in\n"
2780                         "\tpipeline port out\n"
2781                         "\tpipeline build\n"
2782                         "\tpipeline table add\n"
2783                         "\tpipeline table delete\n"
2784                         "\tpipeline table default\n"
2785                         "\tpipeline table show\n"
2786                         "\tpipeline selector group add\n"
2787                         "\tpipeline selector group delete\n"
2788                         "\tpipeline selector group member add\n"
2789                         "\tpipeline selector group member delete\n"
2790                         "\tpipeline selector show\n"
2791                         "\tpipeline learner default\n"
2792                         "\tpipeline commit\n"
2793                         "\tpipeline abort\n"
2794                         "\tpipeline regrd\n"
2795                         "\tpipeline regwr\n"
2796                         "\tpipeline meter profile add\n"
2797                         "\tpipeline meter profile delete\n"
2798                         "\tpipeline meter reset\n"
2799                         "\tpipeline meter set\n"
2800                         "\tpipeline meter stats\n"
2801                         "\tpipeline stats\n"
2802                         "\tthread pipeline enable\n"
2803                         "\tthread pipeline disable\n\n");
2804                 return;
2805         }
2806
2807         if (strcmp(tokens[0], "mempool") == 0) {
2808                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
2809                 return;
2810         }
2811
2812         if (strcmp(tokens[0], "link") == 0) {
2813                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
2814                 return;
2815         }
2816
2817         if (strcmp(tokens[0], "ring") == 0) {
2818                 snprintf(out, out_size, "\n%s\n", cmd_ring_help);
2819                 return;
2820         }
2821
2822         if (strcmp(tokens[0], "tap") == 0) {
2823                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
2824                 return;
2825         }
2826
2827         if ((strcmp(tokens[0], "pipeline") == 0) &&
2828                 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
2829                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
2830                 return;
2831         }
2832
2833         if ((strcmp(tokens[0], "pipeline") == 0) &&
2834                 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
2835                 if (strcmp(tokens[2], "in") == 0) {
2836                         snprintf(out, out_size, "\n%s\n",
2837                                 cmd_pipeline_port_in_help);
2838                         return;
2839                 }
2840
2841                 if (strcmp(tokens[2], "out") == 0) {
2842                         snprintf(out, out_size, "\n%s\n",
2843                                 cmd_pipeline_port_out_help);
2844                         return;
2845                 }
2846         }
2847
2848         if ((strcmp(tokens[0], "pipeline") == 0) &&
2849                 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
2850                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
2851                 return;
2852         }
2853
2854         if ((strcmp(tokens[0], "pipeline") == 0) &&
2855                 (n_tokens == 3) &&
2856                 (strcmp(tokens[1], "table") == 0) &&
2857                 (strcmp(tokens[2], "add") == 0)) {
2858                 snprintf(out, out_size, "\n%s\n",
2859                         cmd_pipeline_table_add_help);
2860                 return;
2861         }
2862
2863         if ((strcmp(tokens[0], "pipeline") == 0) &&
2864                 (n_tokens == 3) &&
2865                 (strcmp(tokens[1], "table") == 0) &&
2866                 (strcmp(tokens[2], "delete") == 0)) {
2867                 snprintf(out, out_size, "\n%s\n",
2868                         cmd_pipeline_table_delete_help);
2869                 return;
2870         }
2871
2872         if ((strcmp(tokens[0], "pipeline") == 0) &&
2873                 (n_tokens == 3) &&
2874                 (strcmp(tokens[1], "table") == 0) &&
2875                 (strcmp(tokens[2], "default") == 0)) {
2876                 snprintf(out, out_size, "\n%s\n",
2877                         cmd_pipeline_table_default_help);
2878                 return;
2879         }
2880
2881         if ((strcmp(tokens[0], "pipeline") == 0) &&
2882                 (n_tokens == 3) &&
2883                 (strcmp(tokens[1], "table") == 0) &&
2884                 (strcmp(tokens[2], "show") == 0)) {
2885                 snprintf(out, out_size, "\n%s\n",
2886                         cmd_pipeline_table_show_help);
2887                 return;
2888         }
2889
2890         if ((strcmp(tokens[0], "pipeline") == 0) &&
2891                 (n_tokens == 4) &&
2892                 (strcmp(tokens[1], "selector") == 0) &&
2893                 (strcmp(tokens[2], "group") == 0) &&
2894                 (strcmp(tokens[3], "add") == 0)) {
2895                 snprintf(out, out_size, "\n%s\n",
2896                         cmd_pipeline_selector_group_add_help);
2897                 return;
2898         }
2899
2900         if ((strcmp(tokens[0], "pipeline") == 0) &&
2901                 (n_tokens == 4) &&
2902                 (strcmp(tokens[1], "selector") == 0) &&
2903                 (strcmp(tokens[2], "group") == 0) &&
2904                 (strcmp(tokens[3], "delete") == 0)) {
2905                 snprintf(out, out_size, "\n%s\n",
2906                         cmd_pipeline_selector_group_delete_help);
2907                 return;
2908         }
2909
2910         if ((strcmp(tokens[0], "pipeline") == 0) &&
2911                 (n_tokens == 5) &&
2912                 (strcmp(tokens[1], "selector") == 0) &&
2913                 (strcmp(tokens[2], "group") == 0) &&
2914                 (strcmp(tokens[3], "member") == 0) &&
2915                 (strcmp(tokens[4], "add") == 0)) {
2916                 snprintf(out, out_size, "\n%s\n",
2917                         cmd_pipeline_selector_group_member_add_help);
2918                 return;
2919         }
2920
2921         if ((strcmp(tokens[0], "pipeline") == 0) &&
2922                 (n_tokens == 5) &&
2923                 (strcmp(tokens[1], "selector") == 0) &&
2924                 (strcmp(tokens[2], "group") == 0) &&
2925                 (strcmp(tokens[3], "member") == 0) &&
2926                 (strcmp(tokens[4], "delete") == 0)) {
2927                 snprintf(out, out_size, "\n%s\n",
2928                         cmd_pipeline_selector_group_member_delete_help);
2929                 return;
2930         }
2931
2932         if ((strcmp(tokens[0], "pipeline") == 0) &&
2933                 (n_tokens == 3) &&
2934                 (strcmp(tokens[1], "selector") == 0) &&
2935                 (strcmp(tokens[2], "show") == 0)) {
2936                 snprintf(out, out_size, "\n%s\n",
2937                         cmd_pipeline_selector_show_help);
2938                 return;
2939         }
2940
2941         if ((strcmp(tokens[0], "pipeline") == 0) &&
2942                 (n_tokens == 3) &&
2943                 (strcmp(tokens[1], "learner") == 0) &&
2944                 (strcmp(tokens[2], "default") == 0)) {
2945                 snprintf(out, out_size, "\n%s\n",
2946                         cmd_pipeline_learner_default_help);
2947                 return;
2948         }
2949
2950         if ((strcmp(tokens[0], "pipeline") == 0) &&
2951                 (n_tokens == 2) &&
2952                 (strcmp(tokens[1], "commit") == 0)) {
2953                 snprintf(out, out_size, "\n%s\n",
2954                         cmd_pipeline_commit_help);
2955                 return;
2956         }
2957
2958         if ((strcmp(tokens[0], "pipeline") == 0) &&
2959                 (n_tokens == 2) &&
2960                 (strcmp(tokens[1], "abort") == 0)) {
2961                 snprintf(out, out_size, "\n%s\n",
2962                         cmd_pipeline_abort_help);
2963                 return;
2964         }
2965
2966         if ((strcmp(tokens[0], "pipeline") == 0) &&
2967                 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) {
2968                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help);
2969                 return;
2970         }
2971
2972         if ((strcmp(tokens[0], "pipeline") == 0) &&
2973                 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) {
2974                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help);
2975                 return;
2976         }
2977
2978         if (!strcmp(tokens[0], "pipeline") &&
2979                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
2980                 && !strcmp(tokens[2], "profile")
2981                 && !strcmp(tokens[3], "add")) {
2982                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help);
2983                 return;
2984         }
2985
2986         if (!strcmp(tokens[0], "pipeline") &&
2987                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
2988                 && !strcmp(tokens[2], "profile")
2989                 && !strcmp(tokens[3], "delete")) {
2990                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help);
2991                 return;
2992         }
2993
2994         if (!strcmp(tokens[0], "pipeline") &&
2995                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
2996                 && !strcmp(tokens[2], "reset")) {
2997                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help);
2998                 return;
2999         }
3000
3001         if (!strcmp(tokens[0], "pipeline") &&
3002                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
3003                 && !strcmp(tokens[2], "set")) {
3004                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help);
3005                 return;
3006         }
3007
3008         if (!strcmp(tokens[0], "pipeline") &&
3009                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
3010                 && !strcmp(tokens[2], "stats")) {
3011                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help);
3012                 return;
3013         }
3014
3015         if ((strcmp(tokens[0], "pipeline") == 0) &&
3016                 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) {
3017                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help);
3018                 return;
3019         }
3020
3021         if ((n_tokens == 3) &&
3022                 (strcmp(tokens[0], "thread") == 0) &&
3023                 (strcmp(tokens[1], "pipeline") == 0)) {
3024                 if (strcmp(tokens[2], "enable") == 0) {
3025                         snprintf(out, out_size, "\n%s\n",
3026                                 cmd_thread_pipeline_enable_help);
3027                         return;
3028                 }
3029
3030                 if (strcmp(tokens[2], "disable") == 0) {
3031                         snprintf(out, out_size, "\n%s\n",
3032                                 cmd_thread_pipeline_disable_help);
3033                         return;
3034                 }
3035         }
3036
3037         snprintf(out, out_size, "Invalid command\n");
3038 }
3039
3040 void
3041 cli_process(char *in, char *out, size_t out_size, void *obj)
3042 {
3043         char *tokens[CMD_MAX_TOKENS];
3044         uint32_t n_tokens = RTE_DIM(tokens);
3045         int status;
3046
3047         if (is_comment(in))
3048                 return;
3049
3050         status = parse_tokenize_string(in, tokens, &n_tokens);
3051         if (status) {
3052                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
3053                 return;
3054         }
3055
3056         if (n_tokens == 0)
3057                 return;
3058
3059         if (strcmp(tokens[0], "help") == 0) {
3060                 cmd_help(tokens, n_tokens, out, out_size, obj);
3061                 return;
3062         }
3063
3064         if (strcmp(tokens[0], "mempool") == 0) {
3065                 cmd_mempool(tokens, n_tokens, out, out_size, obj);
3066                 return;
3067         }
3068
3069         if (strcmp(tokens[0], "link") == 0) {
3070                 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
3071                         cmd_link_show(tokens, n_tokens, out, out_size, obj);
3072                         return;
3073                 }
3074
3075                 cmd_link(tokens, n_tokens, out, out_size, obj);
3076                 return;
3077         }
3078
3079         if (strcmp(tokens[0], "ring") == 0) {
3080                 cmd_ring(tokens, n_tokens, out, out_size, obj);
3081                 return;
3082         }
3083
3084         if (strcmp(tokens[0], "tap") == 0) {
3085                 cmd_tap(tokens, n_tokens, out, out_size, obj);
3086                 return;
3087         }
3088
3089         if (strcmp(tokens[0], "pipeline") == 0) {
3090                 if ((n_tokens >= 3) &&
3091                         (strcmp(tokens[2], "create") == 0)) {
3092                         cmd_pipeline_create(tokens, n_tokens, out, out_size,
3093                                 obj);
3094                         return;
3095                 }
3096
3097                 if ((n_tokens >= 4) &&
3098                         (strcmp(tokens[2], "port") == 0) &&
3099                         (strcmp(tokens[3], "in") == 0)) {
3100                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
3101                                 obj);
3102                         return;
3103                 }
3104
3105                 if ((n_tokens >= 4) &&
3106                         (strcmp(tokens[2], "port") == 0) &&
3107                         (strcmp(tokens[3], "out") == 0)) {
3108                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
3109                                 obj);
3110                         return;
3111                 }
3112
3113                 if ((n_tokens >= 3) &&
3114                         (strcmp(tokens[2], "build") == 0)) {
3115                         cmd_pipeline_build(tokens, n_tokens, out, out_size,
3116                                 obj);
3117                         return;
3118                 }
3119
3120                 if ((n_tokens >= 5) &&
3121                         (strcmp(tokens[2], "table") == 0) &&
3122                         (strcmp(tokens[4], "add") == 0)) {
3123                         cmd_pipeline_table_add(tokens, n_tokens, out,
3124                                 out_size, obj);
3125                         return;
3126                 }
3127
3128                 if ((n_tokens >= 5) &&
3129                         (strcmp(tokens[2], "table") == 0) &&
3130                         (strcmp(tokens[4], "delete") == 0)) {
3131                         cmd_pipeline_table_delete(tokens, n_tokens, out,
3132                                 out_size, obj);
3133                         return;
3134                 }
3135
3136                 if ((n_tokens >= 5) &&
3137                         (strcmp(tokens[2], "table") == 0) &&
3138                         (strcmp(tokens[4], "default") == 0)) {
3139                         cmd_pipeline_table_default(tokens, n_tokens, out,
3140                                 out_size, obj);
3141                         return;
3142                 }
3143
3144                 if ((n_tokens >= 5) &&
3145                         (strcmp(tokens[2], "table") == 0) &&
3146                         (strcmp(tokens[4], "show") == 0)) {
3147                         cmd_pipeline_table_show(tokens, n_tokens, out,
3148                                 out_size, obj);
3149                         return;
3150                 }
3151
3152                 if ((n_tokens >= 6) &&
3153                         (strcmp(tokens[2], "selector") == 0) &&
3154                         (strcmp(tokens[4], "group") == 0) &&
3155                         (strcmp(tokens[5], "add") == 0)) {
3156                         cmd_pipeline_selector_group_add(tokens, n_tokens, out,
3157                                 out_size, obj);
3158                         return;
3159                 }
3160
3161                 if ((n_tokens >= 6) &&
3162                         (strcmp(tokens[2], "selector") == 0) &&
3163                         (strcmp(tokens[4], "group") == 0) &&
3164                         (strcmp(tokens[5], "delete") == 0)) {
3165                         cmd_pipeline_selector_group_delete(tokens, n_tokens, out,
3166                                 out_size, obj);
3167                         return;
3168                 }
3169
3170                 if ((n_tokens >= 7) &&
3171                         (strcmp(tokens[2], "selector") == 0) &&
3172                         (strcmp(tokens[4], "group") == 0) &&
3173                         (strcmp(tokens[5], "member") == 0) &&
3174                         (strcmp(tokens[6], "add") == 0)) {
3175                         cmd_pipeline_selector_group_member_add(tokens, n_tokens, out,
3176                                 out_size, obj);
3177                         return;
3178                 }
3179
3180                 if ((n_tokens >= 7) &&
3181                         (strcmp(tokens[2], "selector") == 0) &&
3182                         (strcmp(tokens[4], "group") == 0) &&
3183                         (strcmp(tokens[5], "member") == 0) &&
3184                         (strcmp(tokens[6], "delete") == 0)) {
3185                         cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out,
3186                                 out_size, obj);
3187                         return;
3188                 }
3189
3190                 if ((n_tokens >= 5) &&
3191                         (strcmp(tokens[2], "selector") == 0) &&
3192                         (strcmp(tokens[4], "show") == 0)) {
3193                         cmd_pipeline_selector_show(tokens, n_tokens, out,
3194                                 out_size, obj);
3195                         return;
3196                 }
3197
3198                 if ((n_tokens >= 5) &&
3199                         (strcmp(tokens[2], "learner") == 0) &&
3200                         (strcmp(tokens[4], "default") == 0)) {
3201                         cmd_pipeline_learner_default(tokens, n_tokens, out,
3202                                 out_size, obj);
3203                         return;
3204                 }
3205
3206                 if ((n_tokens >= 3) &&
3207                         (strcmp(tokens[2], "commit") == 0)) {
3208                         cmd_pipeline_commit(tokens, n_tokens, out,
3209                                 out_size, obj);
3210                         return;
3211                 }
3212
3213                 if ((n_tokens >= 3) &&
3214                         (strcmp(tokens[2], "abort") == 0)) {
3215                         cmd_pipeline_abort(tokens, n_tokens, out,
3216                                 out_size, obj);
3217                         return;
3218                 }
3219
3220                 if ((n_tokens >= 3) &&
3221                         (strcmp(tokens[2], "regrd") == 0)) {
3222                         cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj);
3223                         return;
3224                 }
3225
3226                 if ((n_tokens >= 3) &&
3227                         (strcmp(tokens[2], "regwr") == 0)) {
3228                         cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj);
3229                         return;
3230                 }
3231
3232                 if ((n_tokens >= 6) &&
3233                         (strcmp(tokens[2], "meter") == 0) &&
3234                         (strcmp(tokens[3], "profile") == 0) &&
3235                         (strcmp(tokens[5], "add") == 0)) {
3236                         cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj);
3237                         return;
3238                 }
3239
3240                 if ((n_tokens >= 6) &&
3241                         (strcmp(tokens[2], "meter") == 0) &&
3242                         (strcmp(tokens[3], "profile") == 0) &&
3243                         (strcmp(tokens[5], "delete") == 0)) {
3244                         cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj);
3245                         return;
3246                 }
3247
3248                 if ((n_tokens >= 9) &&
3249                         (strcmp(tokens[2], "meter") == 0) &&
3250                         (strcmp(tokens[8], "reset") == 0)) {
3251                         cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj);
3252                         return;
3253                 }
3254
3255                 if ((n_tokens >= 9) &&
3256                         (strcmp(tokens[2], "meter") == 0) &&
3257                         (strcmp(tokens[8], "set") == 0)) {
3258                         cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj);
3259                         return;
3260                 }
3261
3262                 if ((n_tokens >= 9) &&
3263                         (strcmp(tokens[2], "meter") == 0) &&
3264                         (strcmp(tokens[8], "stats") == 0)) {
3265                         cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj);
3266                         return;
3267                 }
3268
3269                 if ((n_tokens >= 3) &&
3270                         (strcmp(tokens[2], "stats") == 0)) {
3271                         cmd_pipeline_stats(tokens, n_tokens, out, out_size,
3272                                 obj);
3273                         return;
3274                 }
3275         }
3276
3277         if (strcmp(tokens[0], "thread") == 0) {
3278                 if ((n_tokens >= 5) &&
3279                         (strcmp(tokens[4], "enable") == 0)) {
3280                         cmd_thread_pipeline_enable(tokens, n_tokens,
3281                                 out, out_size, obj);
3282                         return;
3283                 }
3284
3285                 if ((n_tokens >= 5) &&
3286                         (strcmp(tokens[4], "disable") == 0)) {
3287                         cmd_thread_pipeline_disable(tokens, n_tokens,
3288                                 out, out_size, obj);
3289                         return;
3290                 }
3291         }
3292
3293         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
3294 }
3295
3296 int
3297 cli_script_process(const char *file_name,
3298         size_t msg_in_len_max,
3299         size_t msg_out_len_max,
3300         void *obj)
3301 {
3302         char *msg_in = NULL, *msg_out = NULL;
3303         FILE *f = NULL;
3304
3305         /* Check input arguments */
3306         if ((file_name == NULL) ||
3307                 (strlen(file_name) == 0) ||
3308                 (msg_in_len_max == 0) ||
3309                 (msg_out_len_max == 0))
3310                 return -EINVAL;
3311
3312         msg_in = malloc(msg_in_len_max + 1);
3313         msg_out = malloc(msg_out_len_max + 1);
3314         if ((msg_in == NULL) ||
3315                 (msg_out == NULL)) {
3316                 free(msg_out);
3317                 free(msg_in);
3318                 return -ENOMEM;
3319         }
3320
3321         /* Open input file */
3322         f = fopen(file_name, "r");
3323         if (f == NULL) {
3324                 free(msg_out);
3325                 free(msg_in);
3326                 return -EIO;
3327         }
3328
3329         /* Read file */
3330         for ( ; ; ) {
3331                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
3332                         break;
3333
3334                 printf("%s", msg_in);
3335                 msg_out[0] = 0;
3336
3337                 cli_process(msg_in,
3338                         msg_out,
3339                         msg_out_len_max,
3340                         obj);
3341
3342                 if (strlen(msg_out))
3343                         printf("%s", msg_out);
3344         }
3345
3346         /* Close file */
3347         fclose(f);
3348         free(msg_out);
3349         free(msg_in);
3350         return 0;
3351 }