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