net: add macro to extract MAC address bytes
[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 const char cmd_pipeline_commit_help[] =
1831 "pipeline <pipeline_name> commit\n";
1832
1833 static void
1834 cmd_pipeline_commit(char **tokens,
1835         uint32_t n_tokens,
1836         char *out,
1837         size_t out_size,
1838         void *obj)
1839 {
1840         struct pipeline *p;
1841         char *pipeline_name;
1842         int status;
1843
1844         if (n_tokens != 3) {
1845                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1846                 return;
1847         }
1848
1849         pipeline_name = tokens[1];
1850         p = pipeline_find(obj, pipeline_name);
1851         if (!p || !p->ctl) {
1852                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1853                 return;
1854         }
1855
1856         status = rte_swx_ctl_pipeline_commit(p->ctl, 1);
1857         if (status)
1858                 snprintf(out, out_size, "Commit failed. "
1859                         "Use \"commit\" to retry or \"abort\" to discard the pending work.\n");
1860 }
1861
1862 static const char cmd_pipeline_abort_help[] =
1863 "pipeline <pipeline_name> abort\n";
1864
1865 static void
1866 cmd_pipeline_abort(char **tokens,
1867         uint32_t n_tokens,
1868         char *out,
1869         size_t out_size,
1870         void *obj)
1871 {
1872         struct pipeline *p;
1873         char *pipeline_name;
1874
1875         if (n_tokens != 3) {
1876                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1877                 return;
1878         }
1879
1880         pipeline_name = tokens[1];
1881         p = pipeline_find(obj, pipeline_name);
1882         if (!p || !p->ctl) {
1883                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1884                 return;
1885         }
1886
1887         rte_swx_ctl_pipeline_abort(p->ctl);
1888 }
1889
1890 static const char cmd_pipeline_regrd_help[] =
1891 "pipeline <pipeline_name> regrd <register_array_name> <index>\n";
1892
1893 static void
1894 cmd_pipeline_regrd(char **tokens,
1895         uint32_t n_tokens,
1896         char *out,
1897         size_t out_size,
1898         void *obj)
1899 {
1900         struct pipeline *p;
1901         const char *name;
1902         uint64_t value;
1903         uint32_t idx;
1904         int status;
1905
1906         if (n_tokens != 5) {
1907                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1908                 return;
1909         }
1910
1911         p = pipeline_find(obj, tokens[1]);
1912         if (!p || !p->ctl) {
1913                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1914                 return;
1915         }
1916
1917         if (strcmp(tokens[2], "regrd")) {
1918                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd");
1919                 return;
1920         }
1921
1922         name = tokens[3];
1923
1924         if (parser_read_uint32(&idx, tokens[4])) {
1925                 snprintf(out, out_size, MSG_ARG_INVALID, "index");
1926                 return;
1927         }
1928
1929         status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);
1930         if (status) {
1931                 snprintf(out, out_size, "Command failed.\n");
1932                 return;
1933         }
1934
1935         snprintf(out, out_size, "0x%" PRIx64 "\n", value);
1936 }
1937
1938 static const char cmd_pipeline_regwr_help[] =
1939 "pipeline <pipeline_name> regwr <register_array_name> <index> <value>\n";
1940
1941 static void
1942 cmd_pipeline_regwr(char **tokens,
1943         uint32_t n_tokens,
1944         char *out,
1945         size_t out_size,
1946         void *obj)
1947 {
1948         struct pipeline *p;
1949         const char *name;
1950         uint64_t value;
1951         uint32_t idx;
1952         int status;
1953
1954         if (n_tokens != 6) {
1955                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1956                 return;
1957         }
1958
1959         p = pipeline_find(obj, tokens[1]);
1960         if (!p || !p->ctl) {
1961                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1962                 return;
1963         }
1964
1965         if (strcmp(tokens[2], "regwr")) {
1966                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr");
1967                 return;
1968         }
1969
1970         name = tokens[3];
1971
1972         if (parser_read_uint32(&idx, tokens[4])) {
1973                 snprintf(out, out_size, MSG_ARG_INVALID, "index");
1974                 return;
1975         }
1976
1977         if (parser_read_uint64(&value, tokens[5])) {
1978                 snprintf(out, out_size, MSG_ARG_INVALID, "value");
1979                 return;
1980         }
1981
1982         status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);
1983         if (status) {
1984                 snprintf(out, out_size, "Command failed.\n");
1985                 return;
1986         }
1987 }
1988
1989 static const char cmd_pipeline_meter_profile_add_help[] =
1990 "pipeline <pipeline_name> meter profile <profile_name> add "
1991         "cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
1992
1993 static void
1994 cmd_pipeline_meter_profile_add(char **tokens,
1995         uint32_t n_tokens,
1996         char *out,
1997         size_t out_size,
1998         void *obj)
1999 {
2000         struct rte_meter_trtcm_params params;
2001         struct pipeline *p;
2002         const char *profile_name;
2003         int status;
2004
2005         if (n_tokens != 14) {
2006                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2007                 return;
2008         }
2009
2010         p = pipeline_find(obj, tokens[1]);
2011         if (!p || !p->ctl) {
2012                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2013                 return;
2014         }
2015
2016         if (strcmp(tokens[2], "meter")) {
2017                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2018                 return;
2019         }
2020
2021         if (strcmp(tokens[3], "profile")) {
2022                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
2023                 return;
2024         }
2025
2026         profile_name = tokens[4];
2027
2028         if (strcmp(tokens[5], "add")) {
2029                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
2030                 return;
2031         }
2032
2033         if (strcmp(tokens[6], "cir")) {
2034                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
2035                 return;
2036         }
2037
2038         if (parser_read_uint64(&params.cir, tokens[7])) {
2039                 snprintf(out, out_size, MSG_ARG_INVALID, "cir");
2040                 return;
2041         }
2042
2043         if (strcmp(tokens[8], "pir")) {
2044                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
2045                 return;
2046         }
2047
2048         if (parser_read_uint64(&params.pir, tokens[9])) {
2049                 snprintf(out, out_size, MSG_ARG_INVALID, "pir");
2050                 return;
2051         }
2052
2053         if (strcmp(tokens[10], "cbs")) {
2054                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
2055                 return;
2056         }
2057
2058         if (parser_read_uint64(&params.cbs, tokens[11])) {
2059                 snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
2060                 return;
2061         }
2062
2063         if (strcmp(tokens[12], "pbs")) {
2064                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
2065                 return;
2066         }
2067
2068         if (parser_read_uint64(&params.pbs, tokens[13])) {
2069                 snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
2070                 return;
2071         }
2072
2073         status = rte_swx_ctl_meter_profile_add(p->p, profile_name, &params);
2074         if (status) {
2075                 snprintf(out, out_size, "Command failed.\n");
2076                 return;
2077         }
2078 }
2079
2080 static const char cmd_pipeline_meter_profile_delete_help[] =
2081 "pipeline <pipeline_name> meter profile <profile_name> delete\n";
2082
2083 static void
2084 cmd_pipeline_meter_profile_delete(char **tokens,
2085         uint32_t n_tokens,
2086         char *out,
2087         size_t out_size,
2088         void *obj)
2089 {
2090         struct pipeline *p;
2091         const char *profile_name;
2092         int status;
2093
2094         if (n_tokens != 6) {
2095                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2096                 return;
2097         }
2098
2099         p = pipeline_find(obj, tokens[1]);
2100         if (!p || !p->ctl) {
2101                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2102                 return;
2103         }
2104
2105         if (strcmp(tokens[2], "meter")) {
2106                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2107                 return;
2108         }
2109
2110         if (strcmp(tokens[3], "profile")) {
2111                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
2112                 return;
2113         }
2114
2115         profile_name = tokens[4];
2116
2117         if (strcmp(tokens[5], "delete")) {
2118                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
2119                 return;
2120         }
2121
2122         status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
2123         if (status) {
2124                 snprintf(out, out_size, "Command failed.\n");
2125                 return;
2126         }
2127 }
2128
2129 static const char cmd_pipeline_meter_reset_help[] =
2130 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
2131         "reset\n";
2132
2133 static void
2134 cmd_pipeline_meter_reset(char **tokens,
2135         uint32_t n_tokens,
2136         char *out,
2137         size_t out_size,
2138         void *obj)
2139 {
2140         struct pipeline *p;
2141         const char *name;
2142         uint32_t idx0 = 0, idx1 = 0;
2143
2144         if (n_tokens != 9) {
2145                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2146                 return;
2147         }
2148
2149         p = pipeline_find(obj, tokens[1]);
2150         if (!p || !p->ctl) {
2151                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2152                 return;
2153         }
2154
2155         if (strcmp(tokens[2], "meter")) {
2156                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2157                 return;
2158         }
2159
2160         name = tokens[3];
2161
2162         if (strcmp(tokens[4], "from")) {
2163                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
2164                 return;
2165         }
2166
2167         if (parser_read_uint32(&idx0, tokens[5])) {
2168                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
2169                 return;
2170         }
2171
2172         if (strcmp(tokens[6], "to")) {
2173                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
2174                 return;
2175         }
2176
2177         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
2178                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
2179                 return;
2180         }
2181
2182         if (strcmp(tokens[8], "reset")) {
2183                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset");
2184                 return;
2185         }
2186
2187         for ( ; idx0 <= idx1; idx0++) {
2188                 int status;
2189
2190                 status = rte_swx_ctl_meter_reset(p->p, name, idx0);
2191                 if (status) {
2192                         snprintf(out, out_size, "Command failed for index %u.\n", idx0);
2193                         return;
2194                 }
2195         }
2196 }
2197
2198 static const char cmd_pipeline_meter_set_help[] =
2199 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
2200         "set profile <profile_name>\n";
2201
2202 static void
2203 cmd_pipeline_meter_set(char **tokens,
2204         uint32_t n_tokens,
2205         char *out,
2206         size_t out_size,
2207         void *obj)
2208 {
2209         struct pipeline *p;
2210         const char *name, *profile_name;
2211         uint32_t idx0 = 0, idx1 = 0;
2212
2213         if (n_tokens != 11) {
2214                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2215                 return;
2216         }
2217
2218         p = pipeline_find(obj, tokens[1]);
2219         if (!p || !p->ctl) {
2220                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2221                 return;
2222         }
2223
2224         if (strcmp(tokens[2], "meter")) {
2225                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2226                 return;
2227         }
2228
2229         name = tokens[3];
2230
2231         if (strcmp(tokens[4], "from")) {
2232                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
2233                 return;
2234         }
2235
2236         if (parser_read_uint32(&idx0, tokens[5])) {
2237                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
2238                 return;
2239         }
2240
2241         if (strcmp(tokens[6], "to")) {
2242                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
2243                 return;
2244         }
2245
2246         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
2247                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
2248                 return;
2249         }
2250
2251         if (strcmp(tokens[8], "set")) {
2252                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set");
2253                 return;
2254         }
2255
2256         if (strcmp(tokens[9], "profile")) {
2257                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
2258                 return;
2259         }
2260
2261         profile_name = tokens[10];
2262
2263         for ( ; idx0 <= idx1; idx0++) {
2264                 int status;
2265
2266                 status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
2267                 if (status) {
2268                         snprintf(out, out_size, "Command failed for index %u.\n", idx0);
2269                         return;
2270                 }
2271         }
2272 }
2273
2274 static const char cmd_pipeline_meter_stats_help[] =
2275 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
2276         "stats\n";
2277
2278 static void
2279 cmd_pipeline_meter_stats(char **tokens,
2280         uint32_t n_tokens,
2281         char *out,
2282         size_t out_size,
2283         void *obj)
2284 {
2285         struct rte_swx_ctl_meter_stats stats;
2286         struct pipeline *p;
2287         const char *name;
2288         uint32_t idx0 = 0, idx1 = 0;
2289
2290         if (n_tokens != 9) {
2291                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2292                 return;
2293         }
2294
2295         p = pipeline_find(obj, tokens[1]);
2296         if (!p || !p->ctl) {
2297                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2298                 return;
2299         }
2300
2301         if (strcmp(tokens[2], "meter")) {
2302                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
2303                 return;
2304         }
2305
2306         name = tokens[3];
2307
2308         if (strcmp(tokens[4], "from")) {
2309                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
2310                 return;
2311         }
2312
2313         if (parser_read_uint32(&idx0, tokens[5])) {
2314                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
2315                 return;
2316         }
2317
2318         if (strcmp(tokens[6], "to")) {
2319                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
2320                 return;
2321         }
2322
2323         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
2324                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
2325                 return;
2326         }
2327
2328         if (strcmp(tokens[8], "stats")) {
2329                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2330                 return;
2331         }
2332
2333         /* Table header. */
2334         snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
2335                  "-------",
2336                  "----------------", "----------------", "----------------",
2337                  "----------------", "----------------", "----------------");
2338         out_size -= strlen(out);
2339         out += strlen(out);
2340
2341         snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n",
2342                  "METER #",
2343                  "GREEN (packets)", "YELLOW (packets)", "RED (packets)",
2344                  "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)");
2345         out_size -= strlen(out);
2346         out += strlen(out);
2347
2348         snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
2349                  "-------",
2350                  "----------------", "----------------", "----------------",
2351                  "----------------", "----------------", "----------------");
2352         out_size -= strlen(out);
2353         out += strlen(out);
2354
2355         /* Table rows. */
2356         for ( ; idx0 <= idx1; idx0++) {
2357                 int status;
2358
2359                 status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
2360                 if (status) {
2361                         snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
2362                         out_size -= strlen(out);
2363                         out += strlen(out);
2364                         return;
2365                 }
2366
2367                 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64
2368                          " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n",
2369                          idx0,
2370                          stats.n_pkts[RTE_COLOR_GREEN],
2371                          stats.n_pkts[RTE_COLOR_YELLOW],
2372                          stats.n_pkts[RTE_COLOR_RED],
2373                          stats.n_bytes[RTE_COLOR_GREEN],
2374                          stats.n_bytes[RTE_COLOR_YELLOW],
2375                          stats.n_bytes[RTE_COLOR_RED]);
2376                 out_size -= strlen(out);
2377                 out += strlen(out);
2378         }
2379 }
2380
2381 static const char cmd_pipeline_stats_help[] =
2382 "pipeline <pipeline_name> stats\n";
2383
2384 static void
2385 cmd_pipeline_stats(char **tokens,
2386         uint32_t n_tokens,
2387         char *out,
2388         size_t out_size,
2389         void *obj)
2390 {
2391         struct rte_swx_ctl_pipeline_info info;
2392         struct pipeline *p;
2393         uint32_t i;
2394         int status;
2395
2396         if (n_tokens != 3) {
2397                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2398                 return;
2399         }
2400
2401         p = pipeline_find(obj, tokens[1]);
2402         if (!p || !p->ctl) {
2403                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2404                 return;
2405         }
2406
2407         if (strcmp(tokens[2], "stats")) {
2408                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2409                 return;
2410         }
2411
2412         status = rte_swx_ctl_pipeline_info_get(p->p, &info);
2413         if (status) {
2414                 snprintf(out, out_size, "Pipeline info get error.");
2415                 return;
2416         }
2417
2418         snprintf(out, out_size, "Input ports:\n");
2419         out_size -= strlen(out);
2420         out += strlen(out);
2421
2422         for (i = 0; i < info.n_ports_in; i++) {
2423                 struct rte_swx_port_in_stats stats;
2424
2425                 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
2426
2427                 snprintf(out, out_size, "\tPort %u:"
2428                         " packets %" PRIu64
2429                         " bytes %" PRIu64
2430                         " empty %" PRIu64 "\n",
2431                         i, stats.n_pkts, stats.n_bytes, stats.n_empty);
2432                 out_size -= strlen(out);
2433                 out += strlen(out);
2434         }
2435
2436         snprintf(out, out_size, "\nOutput ports:\n");
2437         out_size -= strlen(out);
2438         out += strlen(out);
2439
2440         for (i = 0; i < info.n_ports_out; i++) {
2441                 struct rte_swx_port_out_stats stats;
2442
2443                 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
2444
2445                 snprintf(out, out_size, "\tPort %u:"
2446                         " packets %" PRIu64
2447                         " bytes %" PRIu64 "\n",
2448                         i, stats.n_pkts, stats.n_bytes);
2449                 out_size -= strlen(out);
2450                 out += strlen(out);
2451         }
2452
2453         snprintf(out, out_size, "\nTables:\n");
2454         out_size -= strlen(out);
2455         out += strlen(out);
2456
2457         for (i = 0; i < info.n_tables; i++) {
2458                 struct rte_swx_ctl_table_info table_info;
2459                 uint64_t n_pkts_action[info.n_actions];
2460                 struct rte_swx_table_stats stats = {
2461                         .n_pkts_hit = 0,
2462                         .n_pkts_miss = 0,
2463                         .n_pkts_action = n_pkts_action,
2464                 };
2465                 uint32_t j;
2466
2467                 status = rte_swx_ctl_table_info_get(p->p, i, &table_info);
2468                 if (status) {
2469                         snprintf(out, out_size, "Table info get error.");
2470                         return;
2471                 }
2472
2473                 status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats);
2474                 if (status) {
2475                         snprintf(out, out_size, "Table stats read error.");
2476                         return;
2477                 }
2478
2479                 snprintf(out, out_size, "\tTable %s:\n"
2480                         "\t\tHit (packets): %" PRIu64 "\n"
2481                         "\t\tMiss (packets): %" PRIu64 "\n",
2482                         table_info.name,
2483                         stats.n_pkts_hit,
2484                         stats.n_pkts_miss);
2485                 out_size -= strlen(out);
2486                 out += strlen(out);
2487
2488                 for (j = 0; j < info.n_actions; j++) {
2489                         struct rte_swx_ctl_action_info action_info;
2490
2491                         status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
2492                         if (status) {
2493                                 snprintf(out, out_size, "Action info get error.");
2494                                 return;
2495                         }
2496
2497                         snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n",
2498                                 action_info.name,
2499                                 stats.n_pkts_action[j]);
2500                         out_size -= strlen(out);
2501                         out += strlen(out);
2502                 }
2503         }
2504 }
2505
2506 static const char cmd_thread_pipeline_enable_help[] =
2507 "thread <thread_id> pipeline <pipeline_name> enable\n";
2508
2509 static void
2510 cmd_thread_pipeline_enable(char **tokens,
2511         uint32_t n_tokens,
2512         char *out,
2513         size_t out_size,
2514         void *obj)
2515 {
2516         char *pipeline_name;
2517         struct pipeline *p;
2518         uint32_t thread_id;
2519         int status;
2520
2521         if (n_tokens != 5) {
2522                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2523                 return;
2524         }
2525
2526         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2527                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2528                 return;
2529         }
2530
2531         if (strcmp(tokens[2], "pipeline") != 0) {
2532                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2533                 return;
2534         }
2535
2536         pipeline_name = tokens[3];
2537         p = pipeline_find(obj, pipeline_name);
2538         if (!p || !p->ctl) {
2539                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2540                 return;
2541         }
2542
2543         if (strcmp(tokens[4], "enable") != 0) {
2544                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2545                 return;
2546         }
2547
2548         status = thread_pipeline_enable(thread_id, obj, pipeline_name);
2549         if (status) {
2550                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
2551                 return;
2552         }
2553 }
2554
2555 static const char cmd_thread_pipeline_disable_help[] =
2556 "thread <thread_id> pipeline <pipeline_name> disable\n";
2557
2558 static void
2559 cmd_thread_pipeline_disable(char **tokens,
2560         uint32_t n_tokens,
2561         char *out,
2562         size_t out_size,
2563         void *obj)
2564 {
2565         struct pipeline *p;
2566         char *pipeline_name;
2567         uint32_t thread_id;
2568         int status;
2569
2570         if (n_tokens != 5) {
2571                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2572                 return;
2573         }
2574
2575         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2576                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2577                 return;
2578         }
2579
2580         if (strcmp(tokens[2], "pipeline") != 0) {
2581                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2582                 return;
2583         }
2584
2585         pipeline_name = tokens[3];
2586         p = pipeline_find(obj, pipeline_name);
2587         if (!p || !p->ctl) {
2588                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2589                 return;
2590         }
2591
2592         if (strcmp(tokens[4], "disable") != 0) {
2593                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2594                 return;
2595         }
2596
2597         status = thread_pipeline_disable(thread_id, obj, pipeline_name);
2598         if (status) {
2599                 snprintf(out, out_size, MSG_CMD_FAIL,
2600                         "thread pipeline disable");
2601                 return;
2602         }
2603 }
2604
2605 static void
2606 cmd_help(char **tokens,
2607          uint32_t n_tokens,
2608          char *out,
2609          size_t out_size,
2610          void *arg __rte_unused)
2611 {
2612         tokens++;
2613         n_tokens--;
2614
2615         if (n_tokens == 0) {
2616                 snprintf(out, out_size,
2617                         "Type 'help <command>' for command details.\n\n"
2618                         "List of commands:\n"
2619                         "\tmempool\n"
2620                         "\tlink\n"
2621                         "\ttap\n"
2622                         "\tpipeline create\n"
2623                         "\tpipeline port in\n"
2624                         "\tpipeline port out\n"
2625                         "\tpipeline build\n"
2626                         "\tpipeline table add\n"
2627                         "\tpipeline table delete\n"
2628                         "\tpipeline table default\n"
2629                         "\tpipeline table show\n"
2630                         "\tpipeline selector group add\n"
2631                         "\tpipeline selector group delete\n"
2632                         "\tpipeline selector group member add\n"
2633                         "\tpipeline selector group member delete\n"
2634                         "\tpipeline selector show\n"
2635                         "\tpipeline commit\n"
2636                         "\tpipeline abort\n"
2637                         "\tpipeline regrd\n"
2638                         "\tpipeline regwr\n"
2639                         "\tpipeline meter profile add\n"
2640                         "\tpipeline meter profile delete\n"
2641                         "\tpipeline meter reset\n"
2642                         "\tpipeline meter set\n"
2643                         "\tpipeline meter stats\n"
2644                         "\tpipeline stats\n"
2645                         "\tthread pipeline enable\n"
2646                         "\tthread pipeline disable\n\n");
2647                 return;
2648         }
2649
2650         if (strcmp(tokens[0], "mempool") == 0) {
2651                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
2652                 return;
2653         }
2654
2655         if (strcmp(tokens[0], "link") == 0) {
2656                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
2657                 return;
2658         }
2659
2660         if (strcmp(tokens[0], "ring") == 0) {
2661                 snprintf(out, out_size, "\n%s\n", cmd_ring_help);
2662                 return;
2663         }
2664
2665         if (strcmp(tokens[0], "tap") == 0) {
2666                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
2667                 return;
2668         }
2669
2670         if ((strcmp(tokens[0], "pipeline") == 0) &&
2671                 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
2672                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
2673                 return;
2674         }
2675
2676         if ((strcmp(tokens[0], "pipeline") == 0) &&
2677                 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
2678                 if (strcmp(tokens[2], "in") == 0) {
2679                         snprintf(out, out_size, "\n%s\n",
2680                                 cmd_pipeline_port_in_help);
2681                         return;
2682                 }
2683
2684                 if (strcmp(tokens[2], "out") == 0) {
2685                         snprintf(out, out_size, "\n%s\n",
2686                                 cmd_pipeline_port_out_help);
2687                         return;
2688                 }
2689         }
2690
2691         if ((strcmp(tokens[0], "pipeline") == 0) &&
2692                 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
2693                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
2694                 return;
2695         }
2696
2697         if ((strcmp(tokens[0], "pipeline") == 0) &&
2698                 (n_tokens == 3) &&
2699                 (strcmp(tokens[1], "table") == 0) &&
2700                 (strcmp(tokens[2], "add") == 0)) {
2701                 snprintf(out, out_size, "\n%s\n",
2702                         cmd_pipeline_table_add_help);
2703                 return;
2704         }
2705
2706         if ((strcmp(tokens[0], "pipeline") == 0) &&
2707                 (n_tokens == 3) &&
2708                 (strcmp(tokens[1], "table") == 0) &&
2709                 (strcmp(tokens[2], "delete") == 0)) {
2710                 snprintf(out, out_size, "\n%s\n",
2711                         cmd_pipeline_table_delete_help);
2712                 return;
2713         }
2714
2715         if ((strcmp(tokens[0], "pipeline") == 0) &&
2716                 (n_tokens == 3) &&
2717                 (strcmp(tokens[1], "table") == 0) &&
2718                 (strcmp(tokens[2], "default") == 0)) {
2719                 snprintf(out, out_size, "\n%s\n",
2720                         cmd_pipeline_table_default_help);
2721                 return;
2722         }
2723
2724         if ((strcmp(tokens[0], "pipeline") == 0) &&
2725                 (n_tokens == 3) &&
2726                 (strcmp(tokens[1], "table") == 0) &&
2727                 (strcmp(tokens[2], "show") == 0)) {
2728                 snprintf(out, out_size, "\n%s\n",
2729                         cmd_pipeline_table_show_help);
2730                 return;
2731         }
2732
2733         if ((strcmp(tokens[0], "pipeline") == 0) &&
2734                 (n_tokens == 4) &&
2735                 (strcmp(tokens[1], "selector") == 0) &&
2736                 (strcmp(tokens[2], "group") == 0) &&
2737                 (strcmp(tokens[3], "add") == 0)) {
2738                 snprintf(out, out_size, "\n%s\n",
2739                         cmd_pipeline_selector_group_add_help);
2740                 return;
2741         }
2742
2743         if ((strcmp(tokens[0], "pipeline") == 0) &&
2744                 (n_tokens == 4) &&
2745                 (strcmp(tokens[1], "selector") == 0) &&
2746                 (strcmp(tokens[2], "group") == 0) &&
2747                 (strcmp(tokens[3], "delete") == 0)) {
2748                 snprintf(out, out_size, "\n%s\n",
2749                         cmd_pipeline_selector_group_delete_help);
2750                 return;
2751         }
2752
2753         if ((strcmp(tokens[0], "pipeline") == 0) &&
2754                 (n_tokens == 5) &&
2755                 (strcmp(tokens[1], "selector") == 0) &&
2756                 (strcmp(tokens[2], "group") == 0) &&
2757                 (strcmp(tokens[3], "member") == 0) &&
2758                 (strcmp(tokens[4], "add") == 0)) {
2759                 snprintf(out, out_size, "\n%s\n",
2760                         cmd_pipeline_selector_group_member_add_help);
2761                 return;
2762         }
2763
2764         if ((strcmp(tokens[0], "pipeline") == 0) &&
2765                 (n_tokens == 5) &&
2766                 (strcmp(tokens[1], "selector") == 0) &&
2767                 (strcmp(tokens[2], "group") == 0) &&
2768                 (strcmp(tokens[3], "member") == 0) &&
2769                 (strcmp(tokens[4], "delete") == 0)) {
2770                 snprintf(out, out_size, "\n%s\n",
2771                         cmd_pipeline_selector_group_member_delete_help);
2772                 return;
2773         }
2774
2775         if ((strcmp(tokens[0], "pipeline") == 0) &&
2776                 (n_tokens == 3) &&
2777                 (strcmp(tokens[1], "selector") == 0) &&
2778                 (strcmp(tokens[2], "show") == 0)) {
2779                 snprintf(out, out_size, "\n%s\n",
2780                         cmd_pipeline_selector_show_help);
2781                 return;
2782         }
2783
2784         if ((strcmp(tokens[0], "pipeline") == 0) &&
2785                 (n_tokens == 2) &&
2786                 (strcmp(tokens[1], "commit") == 0)) {
2787                 snprintf(out, out_size, "\n%s\n",
2788                         cmd_pipeline_commit_help);
2789                 return;
2790         }
2791
2792         if ((strcmp(tokens[0], "pipeline") == 0) &&
2793                 (n_tokens == 2) &&
2794                 (strcmp(tokens[1], "abort") == 0)) {
2795                 snprintf(out, out_size, "\n%s\n",
2796                         cmd_pipeline_abort_help);
2797                 return;
2798         }
2799
2800         if ((strcmp(tokens[0], "pipeline") == 0) &&
2801                 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) {
2802                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help);
2803                 return;
2804         }
2805
2806         if ((strcmp(tokens[0], "pipeline") == 0) &&
2807                 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) {
2808                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help);
2809                 return;
2810         }
2811
2812         if (!strcmp(tokens[0], "pipeline") &&
2813                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
2814                 && !strcmp(tokens[2], "profile")
2815                 && !strcmp(tokens[3], "add")) {
2816                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help);
2817                 return;
2818         }
2819
2820         if (!strcmp(tokens[0], "pipeline") &&
2821                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
2822                 && !strcmp(tokens[2], "profile")
2823                 && !strcmp(tokens[3], "delete")) {
2824                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help);
2825                 return;
2826         }
2827
2828         if (!strcmp(tokens[0], "pipeline") &&
2829                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
2830                 && !strcmp(tokens[2], "reset")) {
2831                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help);
2832                 return;
2833         }
2834
2835         if (!strcmp(tokens[0], "pipeline") &&
2836                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
2837                 && !strcmp(tokens[2], "set")) {
2838                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help);
2839                 return;
2840         }
2841
2842         if (!strcmp(tokens[0], "pipeline") &&
2843                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
2844                 && !strcmp(tokens[2], "stats")) {
2845                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help);
2846                 return;
2847         }
2848
2849         if ((strcmp(tokens[0], "pipeline") == 0) &&
2850                 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) {
2851                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help);
2852                 return;
2853         }
2854
2855         if ((n_tokens == 3) &&
2856                 (strcmp(tokens[0], "thread") == 0) &&
2857                 (strcmp(tokens[1], "pipeline") == 0)) {
2858                 if (strcmp(tokens[2], "enable") == 0) {
2859                         snprintf(out, out_size, "\n%s\n",
2860                                 cmd_thread_pipeline_enable_help);
2861                         return;
2862                 }
2863
2864                 if (strcmp(tokens[2], "disable") == 0) {
2865                         snprintf(out, out_size, "\n%s\n",
2866                                 cmd_thread_pipeline_disable_help);
2867                         return;
2868                 }
2869         }
2870
2871         snprintf(out, out_size, "Invalid command\n");
2872 }
2873
2874 void
2875 cli_process(char *in, char *out, size_t out_size, void *obj)
2876 {
2877         char *tokens[CMD_MAX_TOKENS];
2878         uint32_t n_tokens = RTE_DIM(tokens);
2879         int status;
2880
2881         if (is_comment(in))
2882                 return;
2883
2884         status = parse_tokenize_string(in, tokens, &n_tokens);
2885         if (status) {
2886                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
2887                 return;
2888         }
2889
2890         if (n_tokens == 0)
2891                 return;
2892
2893         if (strcmp(tokens[0], "help") == 0) {
2894                 cmd_help(tokens, n_tokens, out, out_size, obj);
2895                 return;
2896         }
2897
2898         if (strcmp(tokens[0], "mempool") == 0) {
2899                 cmd_mempool(tokens, n_tokens, out, out_size, obj);
2900                 return;
2901         }
2902
2903         if (strcmp(tokens[0], "link") == 0) {
2904                 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
2905                         cmd_link_show(tokens, n_tokens, out, out_size, obj);
2906                         return;
2907                 }
2908
2909                 cmd_link(tokens, n_tokens, out, out_size, obj);
2910                 return;
2911         }
2912
2913         if (strcmp(tokens[0], "ring") == 0) {
2914                 cmd_ring(tokens, n_tokens, out, out_size, obj);
2915                 return;
2916         }
2917
2918         if (strcmp(tokens[0], "tap") == 0) {
2919                 cmd_tap(tokens, n_tokens, out, out_size, obj);
2920                 return;
2921         }
2922
2923         if (strcmp(tokens[0], "pipeline") == 0) {
2924                 if ((n_tokens >= 3) &&
2925                         (strcmp(tokens[2], "create") == 0)) {
2926                         cmd_pipeline_create(tokens, n_tokens, out, out_size,
2927                                 obj);
2928                         return;
2929                 }
2930
2931                 if ((n_tokens >= 4) &&
2932                         (strcmp(tokens[2], "port") == 0) &&
2933                         (strcmp(tokens[3], "in") == 0)) {
2934                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
2935                                 obj);
2936                         return;
2937                 }
2938
2939                 if ((n_tokens >= 4) &&
2940                         (strcmp(tokens[2], "port") == 0) &&
2941                         (strcmp(tokens[3], "out") == 0)) {
2942                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
2943                                 obj);
2944                         return;
2945                 }
2946
2947                 if ((n_tokens >= 3) &&
2948                         (strcmp(tokens[2], "build") == 0)) {
2949                         cmd_pipeline_build(tokens, n_tokens, out, out_size,
2950                                 obj);
2951                         return;
2952                 }
2953
2954                 if ((n_tokens >= 5) &&
2955                         (strcmp(tokens[2], "table") == 0) &&
2956                         (strcmp(tokens[4], "add") == 0)) {
2957                         cmd_pipeline_table_add(tokens, n_tokens, out,
2958                                 out_size, obj);
2959                         return;
2960                 }
2961
2962                 if ((n_tokens >= 5) &&
2963                         (strcmp(tokens[2], "table") == 0) &&
2964                         (strcmp(tokens[4], "delete") == 0)) {
2965                         cmd_pipeline_table_delete(tokens, n_tokens, out,
2966                                 out_size, obj);
2967                         return;
2968                 }
2969
2970                 if ((n_tokens >= 5) &&
2971                         (strcmp(tokens[2], "table") == 0) &&
2972                         (strcmp(tokens[4], "default") == 0)) {
2973                         cmd_pipeline_table_default(tokens, n_tokens, out,
2974                                 out_size, obj);
2975                         return;
2976                 }
2977
2978                 if ((n_tokens >= 5) &&
2979                         (strcmp(tokens[2], "table") == 0) &&
2980                         (strcmp(tokens[4], "show") == 0)) {
2981                         cmd_pipeline_table_show(tokens, n_tokens, out,
2982                                 out_size, obj);
2983                         return;
2984                 }
2985
2986                 if ((n_tokens >= 6) &&
2987                         (strcmp(tokens[2], "selector") == 0) &&
2988                         (strcmp(tokens[4], "group") == 0) &&
2989                         (strcmp(tokens[5], "add") == 0)) {
2990                         cmd_pipeline_selector_group_add(tokens, n_tokens, out,
2991                                 out_size, obj);
2992                         return;
2993                 }
2994
2995                 if ((n_tokens >= 6) &&
2996                         (strcmp(tokens[2], "selector") == 0) &&
2997                         (strcmp(tokens[4], "group") == 0) &&
2998                         (strcmp(tokens[5], "delete") == 0)) {
2999                         cmd_pipeline_selector_group_delete(tokens, n_tokens, out,
3000                                 out_size, obj);
3001                         return;
3002                 }
3003
3004                 if ((n_tokens >= 7) &&
3005                         (strcmp(tokens[2], "selector") == 0) &&
3006                         (strcmp(tokens[4], "group") == 0) &&
3007                         (strcmp(tokens[5], "member") == 0) &&
3008                         (strcmp(tokens[6], "add") == 0)) {
3009                         cmd_pipeline_selector_group_member_add(tokens, n_tokens, out,
3010                                 out_size, obj);
3011                         return;
3012                 }
3013
3014                 if ((n_tokens >= 7) &&
3015                         (strcmp(tokens[2], "selector") == 0) &&
3016                         (strcmp(tokens[4], "group") == 0) &&
3017                         (strcmp(tokens[5], "member") == 0) &&
3018                         (strcmp(tokens[6], "delete") == 0)) {
3019                         cmd_pipeline_selector_group_member_delete(tokens, n_tokens, out,
3020                                 out_size, obj);
3021                         return;
3022                 }
3023
3024                 if ((n_tokens >= 5) &&
3025                         (strcmp(tokens[2], "selector") == 0) &&
3026                         (strcmp(tokens[4], "show") == 0)) {
3027                         cmd_pipeline_selector_show(tokens, n_tokens, out,
3028                                 out_size, obj);
3029                         return;
3030                 }
3031
3032                 if ((n_tokens >= 3) &&
3033                         (strcmp(tokens[2], "commit") == 0)) {
3034                         cmd_pipeline_commit(tokens, n_tokens, out,
3035                                 out_size, obj);
3036                         return;
3037                 }
3038
3039                 if ((n_tokens >= 3) &&
3040                         (strcmp(tokens[2], "abort") == 0)) {
3041                         cmd_pipeline_abort(tokens, n_tokens, out,
3042                                 out_size, obj);
3043                         return;
3044                 }
3045
3046                 if ((n_tokens >= 3) &&
3047                         (strcmp(tokens[2], "regrd") == 0)) {
3048                         cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj);
3049                         return;
3050                 }
3051
3052                 if ((n_tokens >= 3) &&
3053                         (strcmp(tokens[2], "regwr") == 0)) {
3054                         cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj);
3055                         return;
3056                 }
3057
3058                 if ((n_tokens >= 6) &&
3059                         (strcmp(tokens[2], "meter") == 0) &&
3060                         (strcmp(tokens[3], "profile") == 0) &&
3061                         (strcmp(tokens[5], "add") == 0)) {
3062                         cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj);
3063                         return;
3064                 }
3065
3066                 if ((n_tokens >= 6) &&
3067                         (strcmp(tokens[2], "meter") == 0) &&
3068                         (strcmp(tokens[3], "profile") == 0) &&
3069                         (strcmp(tokens[5], "delete") == 0)) {
3070                         cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj);
3071                         return;
3072                 }
3073
3074                 if ((n_tokens >= 9) &&
3075                         (strcmp(tokens[2], "meter") == 0) &&
3076                         (strcmp(tokens[8], "reset") == 0)) {
3077                         cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj);
3078                         return;
3079                 }
3080
3081                 if ((n_tokens >= 9) &&
3082                         (strcmp(tokens[2], "meter") == 0) &&
3083                         (strcmp(tokens[8], "set") == 0)) {
3084                         cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj);
3085                         return;
3086                 }
3087
3088                 if ((n_tokens >= 9) &&
3089                         (strcmp(tokens[2], "meter") == 0) &&
3090                         (strcmp(tokens[8], "stats") == 0)) {
3091                         cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj);
3092                         return;
3093                 }
3094
3095                 if ((n_tokens >= 3) &&
3096                         (strcmp(tokens[2], "stats") == 0)) {
3097                         cmd_pipeline_stats(tokens, n_tokens, out, out_size,
3098                                 obj);
3099                         return;
3100                 }
3101         }
3102
3103         if (strcmp(tokens[0], "thread") == 0) {
3104                 if ((n_tokens >= 5) &&
3105                         (strcmp(tokens[4], "enable") == 0)) {
3106                         cmd_thread_pipeline_enable(tokens, n_tokens,
3107                                 out, out_size, obj);
3108                         return;
3109                 }
3110
3111                 if ((n_tokens >= 5) &&
3112                         (strcmp(tokens[4], "disable") == 0)) {
3113                         cmd_thread_pipeline_disable(tokens, n_tokens,
3114                                 out, out_size, obj);
3115                         return;
3116                 }
3117         }
3118
3119         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
3120 }
3121
3122 int
3123 cli_script_process(const char *file_name,
3124         size_t msg_in_len_max,
3125         size_t msg_out_len_max,
3126         void *obj)
3127 {
3128         char *msg_in = NULL, *msg_out = NULL;
3129         FILE *f = NULL;
3130
3131         /* Check input arguments */
3132         if ((file_name == NULL) ||
3133                 (strlen(file_name) == 0) ||
3134                 (msg_in_len_max == 0) ||
3135                 (msg_out_len_max == 0))
3136                 return -EINVAL;
3137
3138         msg_in = malloc(msg_in_len_max + 1);
3139         msg_out = malloc(msg_out_len_max + 1);
3140         if ((msg_in == NULL) ||
3141                 (msg_out == NULL)) {
3142                 free(msg_out);
3143                 free(msg_in);
3144                 return -ENOMEM;
3145         }
3146
3147         /* Open input file */
3148         f = fopen(file_name, "r");
3149         if (f == NULL) {
3150                 free(msg_out);
3151                 free(msg_in);
3152                 return -EIO;
3153         }
3154
3155         /* Read file */
3156         for ( ; ; ) {
3157                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
3158                         break;
3159
3160                 printf("%s", msg_in);
3161                 msg_out[0] = 0;
3162
3163                 cli_process(msg_in,
3164                         msg_out,
3165                         msg_out_len_max,
3166                         obj);
3167
3168                 if (strlen(msg_out))
3169                         printf("%s", msg_out);
3170         }
3171
3172         /* Close file */
3173         fclose(f);
3174         free(msg_out);
3175         free(msg_in);
3176         return 0;
3177 }