pipeline: add meter array to SWX
[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 %02X:%02X:%02X:%02X:%02X:%02X 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 static const char cmd_pipeline_table_update_help[] =
1042 "pipeline <pipeline_name> table <table_name> update <file_name_add> "
1043 "<file_name_delete> <file_name_default>";
1044
1045 static void
1046 cmd_pipeline_table_update(char **tokens,
1047         uint32_t n_tokens,
1048         char *out,
1049         size_t out_size,
1050         void *obj)
1051 {
1052         struct pipeline *p;
1053         char *pipeline_name, *table_name, *line = NULL;
1054         char *file_name_add, *file_name_delete, *file_name_default;
1055         FILE *file_add = NULL, *file_delete = NULL, *file_default = NULL;
1056         uint32_t line_id;
1057         int status;
1058
1059         if (n_tokens != 8) {
1060                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1061                 return;
1062         }
1063
1064         pipeline_name = tokens[1];
1065         p = pipeline_find(obj, pipeline_name);
1066         if (!p || !p->ctl) {
1067                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1068                 return;
1069         }
1070
1071         if (strcmp(tokens[2], "table") != 0) {
1072                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1073                 return;
1074         }
1075
1076         table_name = tokens[3];
1077
1078         if (strcmp(tokens[4], "update") != 0) {
1079                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "update");
1080                 return;
1081         }
1082
1083         file_name_add = tokens[5];
1084         file_name_delete = tokens[6];
1085         file_name_default = tokens[7];
1086
1087         /* File open. */
1088         if (strcmp(file_name_add, "none")) {
1089                 file_add = fopen(file_name_add, "r");
1090                 if (!file_add) {
1091                         snprintf(out, out_size, "Cannot open file %s",
1092                                 file_name_add);
1093                         goto error;
1094                 }
1095         }
1096
1097         if (strcmp(file_name_delete, "none")) {
1098                 file_delete = fopen(file_name_delete, "r");
1099                 if (!file_delete) {
1100                         snprintf(out, out_size, "Cannot open file %s",
1101                                 file_name_delete);
1102                         goto error;
1103                 }
1104         }
1105
1106         if (strcmp(file_name_default, "none")) {
1107                 file_default = fopen(file_name_default, "r");
1108                 if (!file_default) {
1109                         snprintf(out, out_size, "Cannot open file %s",
1110                                 file_name_default);
1111                         goto error;
1112                 }
1113         }
1114
1115         if (!file_add && !file_delete && !file_default) {
1116                 snprintf(out, out_size, "Nothing to be done.");
1117                 return;
1118         }
1119
1120         /* Buffer allocation. */
1121         line = malloc(2048);
1122         if (!line) {
1123                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
1124                 goto error;
1125         }
1126
1127         /* Add. */
1128         if (file_add)
1129                 for (line_id = 1; ; line_id++) {
1130                         struct rte_swx_table_entry *entry;
1131                         int is_blank_or_comment;
1132
1133                         if (fgets(line, 2048, file_add) == NULL)
1134                                 break;
1135
1136                         entry = rte_swx_ctl_pipeline_table_entry_read(p->ctl,
1137                                 table_name,
1138                                 line,
1139                                 &is_blank_or_comment);
1140                         if (!entry) {
1141                                 if (is_blank_or_comment)
1142                                         continue;
1143
1144                                 snprintf(out, out_size, MSG_FILE_ERR,
1145                                         file_name_add, line_id);
1146                                 goto error;
1147                         }
1148
1149                         status = rte_swx_ctl_pipeline_table_entry_add(p->ctl,
1150                                 table_name,
1151                                 entry);
1152                         table_entry_free(entry);
1153                         if (status) {
1154                                 snprintf(out, out_size,
1155                                         "Invalid entry in file %s at line %u",
1156                                         file_name_add, line_id);
1157                                 goto error;
1158                         }
1159                 }
1160
1161
1162         /* Delete. */
1163         if (file_delete)
1164                 for (line_id = 1; ; line_id++) {
1165                         struct rte_swx_table_entry *entry;
1166                         int is_blank_or_comment;
1167
1168                         if (fgets(line, 2048, file_delete) == NULL)
1169                                 break;
1170
1171                         entry = rte_swx_ctl_pipeline_table_entry_read(p->ctl,
1172                                 table_name,
1173                                 line,
1174                                 &is_blank_or_comment);
1175                         if (!entry) {
1176                                 if (is_blank_or_comment)
1177                                         continue;
1178
1179                                 snprintf(out, out_size, MSG_FILE_ERR,
1180                                         file_name_delete, line_id);
1181                                 goto error;
1182                         }
1183
1184                         status = rte_swx_ctl_pipeline_table_entry_delete(p->ctl,
1185                                 table_name,
1186                                 entry);
1187                         table_entry_free(entry);
1188                         if (status)  {
1189                                 snprintf(out, out_size,
1190                                         "Invalid entry in file %s at line %u",
1191                                         file_name_delete, line_id);
1192                                 goto error;
1193                         }
1194                 }
1195
1196         /* Default. */
1197         if (file_default)
1198                 for (line_id = 1; ; line_id++) {
1199                         struct rte_swx_table_entry *entry;
1200                         int is_blank_or_comment;
1201
1202                         if (fgets(line, 2048, file_default) == NULL)
1203                                 break;
1204
1205                         entry = rte_swx_ctl_pipeline_table_entry_read(p->ctl,
1206                                 table_name,
1207                                 line,
1208                                 &is_blank_or_comment);
1209                         if (!entry) {
1210                                 if (is_blank_or_comment)
1211                                         continue;
1212
1213                                 snprintf(out, out_size, MSG_FILE_ERR,
1214                                         file_name_default, line_id);
1215                                 goto error;
1216                         }
1217
1218                         status = rte_swx_ctl_pipeline_table_default_entry_add(p->ctl,
1219                                 table_name,
1220                                 entry);
1221                         table_entry_free(entry);
1222                         if (status) {
1223                                 snprintf(out, out_size,
1224                                         "Invalid entry in file %s at line %u",
1225                                         file_name_default, line_id);
1226                                 goto error;
1227                         }
1228                 }
1229
1230         status = rte_swx_ctl_pipeline_commit(p->ctl, 1);
1231         if (status) {
1232                 snprintf(out, out_size, "Commit failed.");
1233                 goto error;
1234         }
1235
1236
1237         rte_swx_ctl_pipeline_table_fprintf(stdout, p->ctl, table_name);
1238
1239         free(line);
1240         if (file_add)
1241                 fclose(file_add);
1242         if (file_delete)
1243                 fclose(file_delete);
1244         if (file_default)
1245                 fclose(file_default);
1246         return;
1247
1248 error:
1249         rte_swx_ctl_pipeline_abort(p->ctl);
1250         free(line);
1251         if (file_add)
1252                 fclose(file_add);
1253         if (file_delete)
1254                 fclose(file_delete);
1255         if (file_default)
1256                 fclose(file_default);
1257 }
1258
1259 static const char cmd_pipeline_regrd_help[] =
1260 "pipeline <pipeline_name> regrd <register_array_name> <index>\n";
1261
1262 static void
1263 cmd_pipeline_regrd(char **tokens,
1264         uint32_t n_tokens,
1265         char *out,
1266         size_t out_size,
1267         void *obj)
1268 {
1269         struct pipeline *p;
1270         const char *name;
1271         uint64_t value;
1272         uint32_t idx;
1273         int status;
1274
1275         if (n_tokens != 5) {
1276                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1277                 return;
1278         }
1279
1280         p = pipeline_find(obj, tokens[1]);
1281         if (!p || !p->ctl) {
1282                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1283                 return;
1284         }
1285
1286         if (strcmp(tokens[2], "regrd")) {
1287                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd");
1288                 return;
1289         }
1290
1291         name = tokens[3];
1292
1293         if (parser_read_uint32(&idx, tokens[4])) {
1294                 snprintf(out, out_size, MSG_ARG_INVALID, "index");
1295                 return;
1296         }
1297
1298         status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);
1299         if (status) {
1300                 snprintf(out, out_size, "Command failed.\n");
1301                 return;
1302         }
1303
1304         snprintf(out, out_size, "0x%" PRIx64 "\n", value);
1305 }
1306
1307 static const char cmd_pipeline_regwr_help[] =
1308 "pipeline <pipeline_name> regwr <register_array_name> <index> <value>\n";
1309
1310 static void
1311 cmd_pipeline_regwr(char **tokens,
1312         uint32_t n_tokens,
1313         char *out,
1314         size_t out_size,
1315         void *obj)
1316 {
1317         struct pipeline *p;
1318         const char *name;
1319         uint64_t value;
1320         uint32_t idx;
1321         int status;
1322
1323         if (n_tokens != 6) {
1324                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1325                 return;
1326         }
1327
1328         p = pipeline_find(obj, tokens[1]);
1329         if (!p || !p->ctl) {
1330                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1331                 return;
1332         }
1333
1334         if (strcmp(tokens[2], "regwr")) {
1335                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr");
1336                 return;
1337         }
1338
1339         name = tokens[3];
1340
1341         if (parser_read_uint32(&idx, tokens[4])) {
1342                 snprintf(out, out_size, MSG_ARG_INVALID, "index");
1343                 return;
1344         }
1345
1346         if (parser_read_uint64(&value, tokens[5])) {
1347                 snprintf(out, out_size, MSG_ARG_INVALID, "value");
1348                 return;
1349         }
1350
1351         status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);
1352         if (status) {
1353                 snprintf(out, out_size, "Command failed.\n");
1354                 return;
1355         }
1356 }
1357
1358 static const char cmd_pipeline_meter_profile_add_help[] =
1359 "pipeline <pipeline_name> meter profile <profile_name> add "
1360         "cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
1361
1362 static void
1363 cmd_pipeline_meter_profile_add(char **tokens,
1364         uint32_t n_tokens,
1365         char *out,
1366         size_t out_size,
1367         void *obj)
1368 {
1369         struct rte_meter_trtcm_params params;
1370         struct pipeline *p;
1371         const char *profile_name;
1372         int status;
1373
1374         if (n_tokens != 14) {
1375                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1376                 return;
1377         }
1378
1379         p = pipeline_find(obj, tokens[1]);
1380         if (!p || !p->ctl) {
1381                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1382                 return;
1383         }
1384
1385         if (strcmp(tokens[2], "meter")) {
1386                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1387                 return;
1388         }
1389
1390         if (strcmp(tokens[3], "profile")) {
1391                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1392                 return;
1393         }
1394
1395         profile_name = tokens[4];
1396
1397         if (strcmp(tokens[5], "add")) {
1398                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
1399                 return;
1400         }
1401
1402         if (strcmp(tokens[6], "cir")) {
1403                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
1404                 return;
1405         }
1406
1407         if (parser_read_uint64(&params.cir, tokens[7])) {
1408                 snprintf(out, out_size, MSG_ARG_INVALID, "cir");
1409                 return;
1410         }
1411
1412         if (strcmp(tokens[8], "pir")) {
1413                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
1414                 return;
1415         }
1416
1417         if (parser_read_uint64(&params.pir, tokens[9])) {
1418                 snprintf(out, out_size, MSG_ARG_INVALID, "pir");
1419                 return;
1420         }
1421
1422         if (strcmp(tokens[10], "cbs")) {
1423                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
1424                 return;
1425         }
1426
1427         if (parser_read_uint64(&params.cbs, tokens[11])) {
1428                 snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
1429                 return;
1430         }
1431
1432         if (strcmp(tokens[12], "pbs")) {
1433                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
1434                 return;
1435         }
1436
1437         if (parser_read_uint64(&params.pbs, tokens[13])) {
1438                 snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
1439                 return;
1440         }
1441
1442         status = rte_swx_ctl_meter_profile_add(p->p, profile_name, &params);
1443         if (status) {
1444                 snprintf(out, out_size, "Command failed.\n");
1445                 return;
1446         }
1447 }
1448
1449 static const char cmd_pipeline_meter_profile_delete_help[] =
1450 "pipeline <pipeline_name> meter profile <profile_name> delete\n";
1451
1452 static void
1453 cmd_pipeline_meter_profile_delete(char **tokens,
1454         uint32_t n_tokens,
1455         char *out,
1456         size_t out_size,
1457         void *obj)
1458 {
1459         struct pipeline *p;
1460         const char *profile_name;
1461         int status;
1462
1463         if (n_tokens != 6) {
1464                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1465                 return;
1466         }
1467
1468         p = pipeline_find(obj, tokens[1]);
1469         if (!p || !p->ctl) {
1470                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1471                 return;
1472         }
1473
1474         if (strcmp(tokens[2], "meter")) {
1475                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1476                 return;
1477         }
1478
1479         if (strcmp(tokens[3], "profile")) {
1480                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1481                 return;
1482         }
1483
1484         profile_name = tokens[4];
1485
1486         if (strcmp(tokens[5], "delete")) {
1487                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
1488                 return;
1489         }
1490
1491         status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
1492         if (status) {
1493                 snprintf(out, out_size, "Command failed.\n");
1494                 return;
1495         }
1496 }
1497
1498 static const char cmd_pipeline_meter_reset_help[] =
1499 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
1500         "reset\n";
1501
1502 static void
1503 cmd_pipeline_meter_reset(char **tokens,
1504         uint32_t n_tokens,
1505         char *out,
1506         size_t out_size,
1507         void *obj)
1508 {
1509         struct pipeline *p;
1510         const char *name;
1511         uint32_t idx0, idx1;
1512
1513         if (n_tokens != 9) {
1514                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1515                 return;
1516         }
1517
1518         p = pipeline_find(obj, tokens[1]);
1519         if (!p || !p->ctl) {
1520                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1521                 return;
1522         }
1523
1524         if (strcmp(tokens[2], "meter")) {
1525                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1526                 return;
1527         }
1528
1529         name = tokens[3];
1530
1531         if (strcmp(tokens[4], "from")) {
1532                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
1533                 return;
1534         }
1535
1536         if (parser_read_uint32(&idx0, tokens[5])) {
1537                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
1538                 return;
1539         }
1540
1541         if (strcmp(tokens[6], "to")) {
1542                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
1543                 return;
1544         }
1545
1546         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
1547                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
1548                 return;
1549         }
1550
1551         if (strcmp(tokens[8], "reset")) {
1552                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset");
1553                 return;
1554         }
1555
1556         for ( ; idx0 <= idx1; idx0++) {
1557                 int status;
1558
1559                 status = rte_swx_ctl_meter_reset(p->p, name, idx0);
1560                 if (status) {
1561                         snprintf(out, out_size, "Command failed for index %u.\n", idx0);
1562                         return;
1563                 }
1564         }
1565 }
1566
1567 static const char cmd_pipeline_meter_set_help[] =
1568 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
1569         "set profile <profile_name>\n";
1570
1571 static void
1572 cmd_pipeline_meter_set(char **tokens,
1573         uint32_t n_tokens,
1574         char *out,
1575         size_t out_size,
1576         void *obj)
1577 {
1578         struct pipeline *p;
1579         const char *name, *profile_name;
1580         uint32_t idx0, idx1;
1581
1582         if (n_tokens != 11) {
1583                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1584                 return;
1585         }
1586
1587         p = pipeline_find(obj, tokens[1]);
1588         if (!p || !p->ctl) {
1589                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1590                 return;
1591         }
1592
1593         if (strcmp(tokens[2], "meter")) {
1594                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1595                 return;
1596         }
1597
1598         name = tokens[3];
1599
1600         if (strcmp(tokens[4], "from")) {
1601                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
1602                 return;
1603         }
1604
1605         if (parser_read_uint32(&idx0, tokens[5])) {
1606                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
1607                 return;
1608         }
1609
1610         if (strcmp(tokens[6], "to")) {
1611                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
1612                 return;
1613         }
1614
1615         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
1616                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
1617                 return;
1618         }
1619
1620         if (strcmp(tokens[8], "set")) {
1621                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set");
1622                 return;
1623         }
1624
1625         if (strcmp(tokens[9], "profile")) {
1626                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1627                 return;
1628         }
1629
1630         profile_name = tokens[10];
1631
1632         for ( ; idx0 <= idx1; idx0++) {
1633                 int status;
1634
1635                 status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
1636                 if (status) {
1637                         snprintf(out, out_size, "Command failed for index %u.\n", idx0);
1638                         return;
1639                 }
1640         }
1641 }
1642
1643 static const char cmd_pipeline_meter_stats_help[] =
1644 "pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> "
1645         "stats\n";
1646
1647 static void
1648 cmd_pipeline_meter_stats(char **tokens,
1649         uint32_t n_tokens,
1650         char *out,
1651         size_t out_size,
1652         void *obj)
1653 {
1654         struct rte_swx_ctl_meter_stats stats;
1655         struct pipeline *p;
1656         const char *name;
1657         uint32_t idx0, idx1;
1658
1659         if (n_tokens != 9) {
1660                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1661                 return;
1662         }
1663
1664         p = pipeline_find(obj, tokens[1]);
1665         if (!p || !p->ctl) {
1666                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1667                 return;
1668         }
1669
1670         if (strcmp(tokens[2], "meter")) {
1671                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1672                 return;
1673         }
1674
1675         name = tokens[3];
1676
1677         if (strcmp(tokens[4], "from")) {
1678                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
1679                 return;
1680         }
1681
1682         if (parser_read_uint32(&idx0, tokens[5])) {
1683                 snprintf(out, out_size, MSG_ARG_INVALID, "index0");
1684                 return;
1685         }
1686
1687         if (strcmp(tokens[6], "to")) {
1688                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
1689                 return;
1690         }
1691
1692         if (parser_read_uint32(&idx1, tokens[7]) || (idx1 < idx0)) {
1693                 snprintf(out, out_size, MSG_ARG_INVALID, "index1");
1694                 return;
1695         }
1696
1697         if (strcmp(tokens[8], "stats")) {
1698                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1699                 return;
1700         }
1701
1702         /* Table header. */
1703         snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
1704                  "-------",
1705                  "----------------", "----------------", "----------------",
1706                  "----------------", "----------------", "----------------");
1707         out_size -= strlen(out);
1708         out += strlen(out);
1709
1710         snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n",
1711                  "METER #",
1712                  "GREEN (packets)", "YELLOW (packets)", "RED (packets)",
1713                  "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)");
1714         out_size -= strlen(out);
1715         out += strlen(out);
1716
1717         snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
1718                  "-------",
1719                  "----------------", "----------------", "----------------",
1720                  "----------------", "----------------", "----------------");
1721         out_size -= strlen(out);
1722         out += strlen(out);
1723
1724         /* Table rows. */
1725         for ( ; idx0 <= idx1; idx0++) {
1726                 int status;
1727
1728                 status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
1729                 if (status) {
1730                         snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
1731                         out_size -= strlen(out);
1732                         out += strlen(out);
1733                         return;
1734                 }
1735
1736                 snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64
1737                          " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n",
1738                          idx0,
1739                          stats.n_pkts[RTE_COLOR_GREEN],
1740                          stats.n_pkts[RTE_COLOR_YELLOW],
1741                          stats.n_pkts[RTE_COLOR_RED],
1742                          stats.n_bytes[RTE_COLOR_GREEN],
1743                          stats.n_bytes[RTE_COLOR_YELLOW],
1744                          stats.n_bytes[RTE_COLOR_RED]);
1745                 out_size -= strlen(out);
1746                 out += strlen(out);
1747         }
1748 }
1749
1750 static const char cmd_pipeline_stats_help[] =
1751 "pipeline <pipeline_name> stats\n";
1752
1753 static void
1754 cmd_pipeline_stats(char **tokens,
1755         uint32_t n_tokens,
1756         char *out,
1757         size_t out_size,
1758         void *obj)
1759 {
1760         struct rte_swx_ctl_pipeline_info info;
1761         struct pipeline *p;
1762         uint32_t i;
1763         int status;
1764
1765         if (n_tokens != 3) {
1766                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1767                 return;
1768         }
1769
1770         p = pipeline_find(obj, tokens[1]);
1771         if (!p || !p->ctl) {
1772                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1773                 return;
1774         }
1775
1776         if (strcmp(tokens[2], "stats")) {
1777                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1778                 return;
1779         }
1780
1781         status = rte_swx_ctl_pipeline_info_get(p->p, &info);
1782         if (status) {
1783                 snprintf(out, out_size, "Pipeline info get error.");
1784                 return;
1785         }
1786
1787         snprintf(out, out_size, "Input ports:\n");
1788         out_size -= strlen(out);
1789         out += strlen(out);
1790
1791         for (i = 0; i < info.n_ports_in; i++) {
1792                 struct rte_swx_port_in_stats stats;
1793
1794                 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
1795
1796                 snprintf(out, out_size, "\tPort %u:"
1797                         " packets %" PRIu64
1798                         " bytes %" PRIu64
1799                         " empty %" PRIu64 "\n",
1800                         i, stats.n_pkts, stats.n_bytes, stats.n_empty);
1801                 out_size -= strlen(out);
1802                 out += strlen(out);
1803         }
1804
1805         snprintf(out, out_size, "Output ports:\n");
1806         out_size -= strlen(out);
1807         out += strlen(out);
1808
1809         for (i = 0; i < info.n_ports_out; i++) {
1810                 struct rte_swx_port_out_stats stats;
1811
1812                 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
1813
1814                 snprintf(out, out_size, "\tPort %u:"
1815                         " packets %" PRIu64
1816                         " bytes %" PRIu64 "\n",
1817                         i, stats.n_pkts, stats.n_bytes);
1818                 out_size -= strlen(out);
1819                 out += strlen(out);
1820         }
1821 }
1822
1823 static const char cmd_thread_pipeline_enable_help[] =
1824 "thread <thread_id> pipeline <pipeline_name> enable\n";
1825
1826 static void
1827 cmd_thread_pipeline_enable(char **tokens,
1828         uint32_t n_tokens,
1829         char *out,
1830         size_t out_size,
1831         void *obj)
1832 {
1833         char *pipeline_name;
1834         struct pipeline *p;
1835         uint32_t thread_id;
1836         int status;
1837
1838         if (n_tokens != 5) {
1839                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1840                 return;
1841         }
1842
1843         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
1844                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
1845                 return;
1846         }
1847
1848         if (strcmp(tokens[2], "pipeline") != 0) {
1849                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
1850                 return;
1851         }
1852
1853         pipeline_name = tokens[3];
1854         p = pipeline_find(obj, pipeline_name);
1855         if (!p || !p->ctl) {
1856                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1857                 return;
1858         }
1859
1860         if (strcmp(tokens[4], "enable") != 0) {
1861                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
1862                 return;
1863         }
1864
1865         status = thread_pipeline_enable(thread_id, obj, pipeline_name);
1866         if (status) {
1867                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
1868                 return;
1869         }
1870 }
1871
1872 static const char cmd_thread_pipeline_disable_help[] =
1873 "thread <thread_id> pipeline <pipeline_name> disable\n";
1874
1875 static void
1876 cmd_thread_pipeline_disable(char **tokens,
1877         uint32_t n_tokens,
1878         char *out,
1879         size_t out_size,
1880         void *obj)
1881 {
1882         struct pipeline *p;
1883         char *pipeline_name;
1884         uint32_t thread_id;
1885         int status;
1886
1887         if (n_tokens != 5) {
1888                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1889                 return;
1890         }
1891
1892         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
1893                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
1894                 return;
1895         }
1896
1897         if (strcmp(tokens[2], "pipeline") != 0) {
1898                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
1899                 return;
1900         }
1901
1902         pipeline_name = tokens[3];
1903         p = pipeline_find(obj, pipeline_name);
1904         if (!p || !p->ctl) {
1905                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1906                 return;
1907         }
1908
1909         if (strcmp(tokens[4], "disable") != 0) {
1910                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
1911                 return;
1912         }
1913
1914         status = thread_pipeline_disable(thread_id, obj, pipeline_name);
1915         if (status) {
1916                 snprintf(out, out_size, MSG_CMD_FAIL,
1917                         "thread pipeline disable");
1918                 return;
1919         }
1920 }
1921
1922 static void
1923 cmd_help(char **tokens,
1924          uint32_t n_tokens,
1925          char *out,
1926          size_t out_size,
1927          void *arg __rte_unused)
1928 {
1929         tokens++;
1930         n_tokens--;
1931
1932         if (n_tokens == 0) {
1933                 snprintf(out, out_size,
1934                         "Type 'help <command>' for command details.\n\n"
1935                         "List of commands:\n"
1936                         "\tmempool\n"
1937                         "\tlink\n"
1938                         "\ttap\n"
1939                         "\tpipeline create\n"
1940                         "\tpipeline port in\n"
1941                         "\tpipeline port out\n"
1942                         "\tpipeline build\n"
1943                         "\tpipeline table update\n"
1944                         "\tpipeline regrd\n"
1945                         "\tpipeline regwr\n"
1946                         "\tpipeline meter profile add\n"
1947                         "\tpipeline meter profile delete\n"
1948                         "\tpipeline meter reset\n"
1949                         "\tpipeline meter set\n"
1950                         "\tpipeline meter stats\n"
1951                         "\tpipeline stats\n"
1952                         "\tthread pipeline enable\n"
1953                         "\tthread pipeline disable\n\n");
1954                 return;
1955         }
1956
1957         if (strcmp(tokens[0], "mempool") == 0) {
1958                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
1959                 return;
1960         }
1961
1962         if (strcmp(tokens[0], "link") == 0) {
1963                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
1964                 return;
1965         }
1966
1967         if (strcmp(tokens[0], "ring") == 0) {
1968                 snprintf(out, out_size, "\n%s\n", cmd_ring_help);
1969                 return;
1970         }
1971
1972         if (strcmp(tokens[0], "tap") == 0) {
1973                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
1974                 return;
1975         }
1976
1977         if ((strcmp(tokens[0], "pipeline") == 0) &&
1978                 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
1979                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
1980                 return;
1981         }
1982
1983         if ((strcmp(tokens[0], "pipeline") == 0) &&
1984                 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
1985                 if (strcmp(tokens[2], "in") == 0) {
1986                         snprintf(out, out_size, "\n%s\n",
1987                                 cmd_pipeline_port_in_help);
1988                         return;
1989                 }
1990
1991                 if (strcmp(tokens[2], "out") == 0) {
1992                         snprintf(out, out_size, "\n%s\n",
1993                                 cmd_pipeline_port_out_help);
1994                         return;
1995                 }
1996         }
1997
1998         if ((strcmp(tokens[0], "pipeline") == 0) &&
1999                 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
2000                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
2001                 return;
2002         }
2003
2004         if ((strcmp(tokens[0], "pipeline") == 0) &&
2005                 (n_tokens == 3) &&
2006                 (strcmp(tokens[1], "table") == 0) &&
2007                 (strcmp(tokens[2], "update") == 0)) {
2008                 snprintf(out, out_size, "\n%s\n",
2009                         cmd_pipeline_table_update_help);
2010                 return;
2011         }
2012
2013         if ((strcmp(tokens[0], "pipeline") == 0) &&
2014                 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) {
2015                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help);
2016                 return;
2017         }
2018
2019         if ((strcmp(tokens[0], "pipeline") == 0) &&
2020                 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) {
2021                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help);
2022                 return;
2023         }
2024
2025         if (!strcmp(tokens[0], "pipeline") &&
2026                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
2027                 && !strcmp(tokens[2], "profile")
2028                 && !strcmp(tokens[3], "add")) {
2029                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_add_help);
2030                 return;
2031         }
2032
2033         if (!strcmp(tokens[0], "pipeline") &&
2034                 (n_tokens == 4) && !strcmp(tokens[1], "meter")
2035                 && !strcmp(tokens[2], "profile")
2036                 && !strcmp(tokens[3], "delete")) {
2037                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_profile_delete_help);
2038                 return;
2039         }
2040
2041         if (!strcmp(tokens[0], "pipeline") &&
2042                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
2043                 && !strcmp(tokens[2], "reset")) {
2044                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_reset_help);
2045                 return;
2046         }
2047
2048         if (!strcmp(tokens[0], "pipeline") &&
2049                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
2050                 && !strcmp(tokens[2], "set")) {
2051                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_set_help);
2052                 return;
2053         }
2054
2055         if (!strcmp(tokens[0], "pipeline") &&
2056                 (n_tokens == 3) && !strcmp(tokens[1], "meter")
2057                 && !strcmp(tokens[2], "stats")) {
2058                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_meter_stats_help);
2059                 return;
2060         }
2061
2062         if ((strcmp(tokens[0], "pipeline") == 0) &&
2063                 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) {
2064                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help);
2065                 return;
2066         }
2067
2068         if ((n_tokens == 3) &&
2069                 (strcmp(tokens[0], "thread") == 0) &&
2070                 (strcmp(tokens[1], "pipeline") == 0)) {
2071                 if (strcmp(tokens[2], "enable") == 0) {
2072                         snprintf(out, out_size, "\n%s\n",
2073                                 cmd_thread_pipeline_enable_help);
2074                         return;
2075                 }
2076
2077                 if (strcmp(tokens[2], "disable") == 0) {
2078                         snprintf(out, out_size, "\n%s\n",
2079                                 cmd_thread_pipeline_disable_help);
2080                         return;
2081                 }
2082         }
2083
2084         snprintf(out, out_size, "Invalid command\n");
2085 }
2086
2087 void
2088 cli_process(char *in, char *out, size_t out_size, void *obj)
2089 {
2090         char *tokens[CMD_MAX_TOKENS];
2091         uint32_t n_tokens = RTE_DIM(tokens);
2092         int status;
2093
2094         if (is_comment(in))
2095                 return;
2096
2097         status = parse_tokenize_string(in, tokens, &n_tokens);
2098         if (status) {
2099                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
2100                 return;
2101         }
2102
2103         if (n_tokens == 0)
2104                 return;
2105
2106         if (strcmp(tokens[0], "help") == 0) {
2107                 cmd_help(tokens, n_tokens, out, out_size, obj);
2108                 return;
2109         }
2110
2111         if (strcmp(tokens[0], "mempool") == 0) {
2112                 cmd_mempool(tokens, n_tokens, out, out_size, obj);
2113                 return;
2114         }
2115
2116         if (strcmp(tokens[0], "link") == 0) {
2117                 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
2118                         cmd_link_show(tokens, n_tokens, out, out_size, obj);
2119                         return;
2120                 }
2121
2122                 cmd_link(tokens, n_tokens, out, out_size, obj);
2123                 return;
2124         }
2125
2126         if (strcmp(tokens[0], "ring") == 0) {
2127                 cmd_ring(tokens, n_tokens, out, out_size, obj);
2128                 return;
2129         }
2130
2131         if (strcmp(tokens[0], "tap") == 0) {
2132                 cmd_tap(tokens, n_tokens, out, out_size, obj);
2133                 return;
2134         }
2135
2136         if (strcmp(tokens[0], "pipeline") == 0) {
2137                 if ((n_tokens >= 3) &&
2138                         (strcmp(tokens[2], "create") == 0)) {
2139                         cmd_pipeline_create(tokens, n_tokens, out, out_size,
2140                                 obj);
2141                         return;
2142                 }
2143
2144                 if ((n_tokens >= 4) &&
2145                         (strcmp(tokens[2], "port") == 0) &&
2146                         (strcmp(tokens[3], "in") == 0)) {
2147                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
2148                                 obj);
2149                         return;
2150                 }
2151
2152                 if ((n_tokens >= 4) &&
2153                         (strcmp(tokens[2], "port") == 0) &&
2154                         (strcmp(tokens[3], "out") == 0)) {
2155                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
2156                                 obj);
2157                         return;
2158                 }
2159
2160                 if ((n_tokens >= 3) &&
2161                         (strcmp(tokens[2], "build") == 0)) {
2162                         cmd_pipeline_build(tokens, n_tokens, out, out_size,
2163                                 obj);
2164                         return;
2165                 }
2166
2167                 if ((n_tokens >= 3) &&
2168                         (strcmp(tokens[2], "table") == 0)) {
2169                         cmd_pipeline_table_update(tokens, n_tokens, out,
2170                                 out_size, obj);
2171                         return;
2172                 }
2173
2174                 if ((n_tokens >= 3) &&
2175                         (strcmp(tokens[2], "regrd") == 0)) {
2176                         cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj);
2177                         return;
2178                 }
2179
2180                 if ((n_tokens >= 3) &&
2181                         (strcmp(tokens[2], "regwr") == 0)) {
2182                         cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj);
2183                         return;
2184                 }
2185
2186                 if ((n_tokens >= 6) &&
2187                         (strcmp(tokens[2], "meter") == 0) &&
2188                         (strcmp(tokens[3], "profile") == 0) &&
2189                         (strcmp(tokens[5], "add") == 0)) {
2190                         cmd_pipeline_meter_profile_add(tokens, n_tokens, out, out_size, obj);
2191                         return;
2192                 }
2193
2194                 if ((n_tokens >= 6) &&
2195                         (strcmp(tokens[2], "meter") == 0) &&
2196                         (strcmp(tokens[3], "profile") == 0) &&
2197                         (strcmp(tokens[5], "delete") == 0)) {
2198                         cmd_pipeline_meter_profile_delete(tokens, n_tokens, out, out_size, obj);
2199                         return;
2200                 }
2201
2202                 if ((n_tokens >= 9) &&
2203                         (strcmp(tokens[2], "meter") == 0) &&
2204                         (strcmp(tokens[8], "reset") == 0)) {
2205                         cmd_pipeline_meter_reset(tokens, n_tokens, out, out_size, obj);
2206                         return;
2207                 }
2208
2209                 if ((n_tokens >= 9) &&
2210                         (strcmp(tokens[2], "meter") == 0) &&
2211                         (strcmp(tokens[8], "set") == 0)) {
2212                         cmd_pipeline_meter_set(tokens, n_tokens, out, out_size, obj);
2213                         return;
2214                 }
2215
2216                 if ((n_tokens >= 9) &&
2217                         (strcmp(tokens[2], "meter") == 0) &&
2218                         (strcmp(tokens[8], "stats") == 0)) {
2219                         cmd_pipeline_meter_stats(tokens, n_tokens, out, out_size, obj);
2220                         return;
2221                 }
2222
2223                 if ((n_tokens >= 3) &&
2224                         (strcmp(tokens[2], "stats") == 0)) {
2225                         cmd_pipeline_stats(tokens, n_tokens, out, out_size,
2226                                 obj);
2227                         return;
2228                 }
2229         }
2230
2231         if (strcmp(tokens[0], "thread") == 0) {
2232                 if ((n_tokens >= 5) &&
2233                         (strcmp(tokens[4], "enable") == 0)) {
2234                         cmd_thread_pipeline_enable(tokens, n_tokens,
2235                                 out, out_size, obj);
2236                         return;
2237                 }
2238
2239                 if ((n_tokens >= 5) &&
2240                         (strcmp(tokens[4], "disable") == 0)) {
2241                         cmd_thread_pipeline_disable(tokens, n_tokens,
2242                                 out, out_size, obj);
2243                         return;
2244                 }
2245         }
2246
2247         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
2248 }
2249
2250 int
2251 cli_script_process(const char *file_name,
2252         size_t msg_in_len_max,
2253         size_t msg_out_len_max,
2254         void *obj)
2255 {
2256         char *msg_in = NULL, *msg_out = NULL;
2257         FILE *f = NULL;
2258
2259         /* Check input arguments */
2260         if ((file_name == NULL) ||
2261                 (strlen(file_name) == 0) ||
2262                 (msg_in_len_max == 0) ||
2263                 (msg_out_len_max == 0))
2264                 return -EINVAL;
2265
2266         msg_in = malloc(msg_in_len_max + 1);
2267         msg_out = malloc(msg_out_len_max + 1);
2268         if ((msg_in == NULL) ||
2269                 (msg_out == NULL)) {
2270                 free(msg_out);
2271                 free(msg_in);
2272                 return -ENOMEM;
2273         }
2274
2275         /* Open input file */
2276         f = fopen(file_name, "r");
2277         if (f == NULL) {
2278                 free(msg_out);
2279                 free(msg_in);
2280                 return -EIO;
2281         }
2282
2283         /* Read file */
2284         for ( ; ; ) {
2285                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
2286                         break;
2287
2288                 printf("%s", msg_in);
2289                 msg_out[0] = 0;
2290
2291                 cli_process(msg_in,
2292                         msg_out,
2293                         msg_out_len_max,
2294                         obj);
2295
2296                 if (strlen(msg_out))
2297                         printf("%s", msg_out);
2298         }
2299
2300         /* Close file */
2301         fclose(f);
2302         free(msg_out);
2303         free(msg_in);
2304         return 0;
2305 }