port: add file descriptor SWX port
[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, 10);
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_stats_help[] =
1260 "pipeline <pipeline_name> stats\n";
1261
1262 static void
1263 cmd_pipeline_stats(char **tokens,
1264         uint32_t n_tokens,
1265         char *out,
1266         size_t out_size,
1267         void *obj)
1268 {
1269         struct rte_swx_ctl_pipeline_info info;
1270         struct pipeline *p;
1271         uint32_t i;
1272         int status;
1273
1274         if (n_tokens != 3) {
1275                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1276                 return;
1277         }
1278
1279         p = pipeline_find(obj, tokens[1]);
1280         if (!p || !p->ctl) {
1281                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1282                 return;
1283         }
1284
1285         if (strcmp(tokens[2], "stats")) {
1286                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1287                 return;
1288         }
1289
1290         status = rte_swx_ctl_pipeline_info_get(p->p, &info);
1291         if (status) {
1292                 snprintf(out, out_size, "Pipeline info get error.");
1293                 return;
1294         }
1295
1296         snprintf(out, out_size, "Input ports:\n");
1297         out_size -= strlen(out);
1298         out += strlen(out);
1299
1300         for (i = 0; i < info.n_ports_in; i++) {
1301                 struct rte_swx_port_in_stats stats;
1302
1303                 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
1304
1305                 snprintf(out, out_size, "\tPort %u:"
1306                         " packets %" PRIu64
1307                         " bytes %" PRIu64
1308                         " empty %" PRIu64 "\n",
1309                         i, stats.n_pkts, stats.n_bytes, stats.n_empty);
1310                 out_size -= strlen(out);
1311                 out += strlen(out);
1312         }
1313
1314         snprintf(out, out_size, "Output ports:\n");
1315         out_size -= strlen(out);
1316         out += strlen(out);
1317
1318         for (i = 0; i < info.n_ports_out; i++) {
1319                 struct rte_swx_port_out_stats stats;
1320
1321                 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
1322
1323                 snprintf(out, out_size, "\tPort %u:"
1324                         " packets %" PRIu64
1325                         " bytes %" PRIu64 "\n",
1326                         i, stats.n_pkts, stats.n_bytes);
1327                 out_size -= strlen(out);
1328                 out += strlen(out);
1329         }
1330 }
1331
1332 static const char cmd_thread_pipeline_enable_help[] =
1333 "thread <thread_id> pipeline <pipeline_name> enable\n";
1334
1335 static void
1336 cmd_thread_pipeline_enable(char **tokens,
1337         uint32_t n_tokens,
1338         char *out,
1339         size_t out_size,
1340         void *obj)
1341 {
1342         char *pipeline_name;
1343         struct pipeline *p;
1344         uint32_t thread_id;
1345         int status;
1346
1347         if (n_tokens != 5) {
1348                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1349                 return;
1350         }
1351
1352         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
1353                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
1354                 return;
1355         }
1356
1357         if (strcmp(tokens[2], "pipeline") != 0) {
1358                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
1359                 return;
1360         }
1361
1362         pipeline_name = tokens[3];
1363         p = pipeline_find(obj, pipeline_name);
1364         if (!p || !p->ctl) {
1365                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1366                 return;
1367         }
1368
1369         if (strcmp(tokens[4], "enable") != 0) {
1370                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
1371                 return;
1372         }
1373
1374         status = thread_pipeline_enable(thread_id, obj, pipeline_name);
1375         if (status) {
1376                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
1377                 return;
1378         }
1379 }
1380
1381 static const char cmd_thread_pipeline_disable_help[] =
1382 "thread <thread_id> pipeline <pipeline_name> disable\n";
1383
1384 static void
1385 cmd_thread_pipeline_disable(char **tokens,
1386         uint32_t n_tokens,
1387         char *out,
1388         size_t out_size,
1389         void *obj)
1390 {
1391         struct pipeline *p;
1392         char *pipeline_name;
1393         uint32_t thread_id;
1394         int status;
1395
1396         if (n_tokens != 5) {
1397                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1398                 return;
1399         }
1400
1401         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
1402                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
1403                 return;
1404         }
1405
1406         if (strcmp(tokens[2], "pipeline") != 0) {
1407                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
1408                 return;
1409         }
1410
1411         pipeline_name = tokens[3];
1412         p = pipeline_find(obj, pipeline_name);
1413         if (!p || !p->ctl) {
1414                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1415                 return;
1416         }
1417
1418         if (strcmp(tokens[4], "disable") != 0) {
1419                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
1420                 return;
1421         }
1422
1423         status = thread_pipeline_disable(thread_id, obj, pipeline_name);
1424         if (status) {
1425                 snprintf(out, out_size, MSG_CMD_FAIL,
1426                         "thread pipeline disable");
1427                 return;
1428         }
1429 }
1430
1431 static void
1432 cmd_help(char **tokens,
1433          uint32_t n_tokens,
1434          char *out,
1435          size_t out_size,
1436          void *arg __rte_unused)
1437 {
1438         tokens++;
1439         n_tokens--;
1440
1441         if (n_tokens == 0) {
1442                 snprintf(out, out_size,
1443                         "Type 'help <command>' for command details.\n\n"
1444                         "List of commands:\n"
1445                         "\tmempool\n"
1446                         "\tlink\n"
1447                         "\ttap\n"
1448                         "\tpipeline create\n"
1449                         "\tpipeline port in\n"
1450                         "\tpipeline port out\n"
1451                         "\tpipeline build\n"
1452                         "\tpipeline table update\n"
1453                         "\tpipeline stats\n"
1454                         "\tthread pipeline enable\n"
1455                         "\tthread pipeline disable\n\n");
1456                 return;
1457         }
1458
1459         if (strcmp(tokens[0], "mempool") == 0) {
1460                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
1461                 return;
1462         }
1463
1464         if (strcmp(tokens[0], "link") == 0) {
1465                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
1466                 return;
1467         }
1468
1469         if (strcmp(tokens[0], "ring") == 0) {
1470                 snprintf(out, out_size, "\n%s\n", cmd_ring_help);
1471                 return;
1472         }
1473
1474         if (strcmp(tokens[0], "tap") == 0) {
1475                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
1476                 return;
1477         }
1478
1479         if ((strcmp(tokens[0], "pipeline") == 0) &&
1480                 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
1481                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
1482                 return;
1483         }
1484
1485         if ((strcmp(tokens[0], "pipeline") == 0) &&
1486                 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
1487                 if (strcmp(tokens[2], "in") == 0) {
1488                         snprintf(out, out_size, "\n%s\n",
1489                                 cmd_pipeline_port_in_help);
1490                         return;
1491                 }
1492
1493                 if (strcmp(tokens[2], "out") == 0) {
1494                         snprintf(out, out_size, "\n%s\n",
1495                                 cmd_pipeline_port_out_help);
1496                         return;
1497                 }
1498         }
1499
1500         if ((strcmp(tokens[0], "pipeline") == 0) &&
1501                 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
1502                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
1503                 return;
1504         }
1505
1506         if ((strcmp(tokens[0], "pipeline") == 0) &&
1507                 (n_tokens == 3) &&
1508                 (strcmp(tokens[1], "table") == 0) &&
1509                 (strcmp(tokens[2], "update") == 0)) {
1510                 snprintf(out, out_size, "\n%s\n",
1511                         cmd_pipeline_table_update_help);
1512                 return;
1513         }
1514
1515         if ((strcmp(tokens[0], "pipeline") == 0) &&
1516                 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) {
1517                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help);
1518                 return;
1519         }
1520
1521         if ((n_tokens == 3) &&
1522                 (strcmp(tokens[0], "thread") == 0) &&
1523                 (strcmp(tokens[1], "pipeline") == 0)) {
1524                 if (strcmp(tokens[2], "enable") == 0) {
1525                         snprintf(out, out_size, "\n%s\n",
1526                                 cmd_thread_pipeline_enable_help);
1527                         return;
1528                 }
1529
1530                 if (strcmp(tokens[2], "disable") == 0) {
1531                         snprintf(out, out_size, "\n%s\n",
1532                                 cmd_thread_pipeline_disable_help);
1533                         return;
1534                 }
1535         }
1536
1537         snprintf(out, out_size, "Invalid command\n");
1538 }
1539
1540 void
1541 cli_process(char *in, char *out, size_t out_size, void *obj)
1542 {
1543         char *tokens[CMD_MAX_TOKENS];
1544         uint32_t n_tokens = RTE_DIM(tokens);
1545         int status;
1546
1547         if (is_comment(in))
1548                 return;
1549
1550         status = parse_tokenize_string(in, tokens, &n_tokens);
1551         if (status) {
1552                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
1553                 return;
1554         }
1555
1556         if (n_tokens == 0)
1557                 return;
1558
1559         if (strcmp(tokens[0], "help") == 0) {
1560                 cmd_help(tokens, n_tokens, out, out_size, obj);
1561                 return;
1562         }
1563
1564         if (strcmp(tokens[0], "mempool") == 0) {
1565                 cmd_mempool(tokens, n_tokens, out, out_size, obj);
1566                 return;
1567         }
1568
1569         if (strcmp(tokens[0], "link") == 0) {
1570                 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
1571                         cmd_link_show(tokens, n_tokens, out, out_size, obj);
1572                         return;
1573                 }
1574
1575                 cmd_link(tokens, n_tokens, out, out_size, obj);
1576                 return;
1577         }
1578
1579         if (strcmp(tokens[0], "ring") == 0) {
1580                 cmd_ring(tokens, n_tokens, out, out_size, obj);
1581                 return;
1582         }
1583
1584         if (strcmp(tokens[0], "tap") == 0) {
1585                 cmd_tap(tokens, n_tokens, out, out_size, obj);
1586                 return;
1587         }
1588
1589         if (strcmp(tokens[0], "pipeline") == 0) {
1590                 if ((n_tokens >= 3) &&
1591                         (strcmp(tokens[2], "create") == 0)) {
1592                         cmd_pipeline_create(tokens, n_tokens, out, out_size,
1593                                 obj);
1594                         return;
1595                 }
1596
1597                 if ((n_tokens >= 4) &&
1598                         (strcmp(tokens[2], "port") == 0) &&
1599                         (strcmp(tokens[3], "in") == 0)) {
1600                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
1601                                 obj);
1602                         return;
1603                 }
1604
1605                 if ((n_tokens >= 4) &&
1606                         (strcmp(tokens[2], "port") == 0) &&
1607                         (strcmp(tokens[3], "out") == 0)) {
1608                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
1609                                 obj);
1610                         return;
1611                 }
1612
1613                 if ((n_tokens >= 3) &&
1614                         (strcmp(tokens[2], "build") == 0)) {
1615                         cmd_pipeline_build(tokens, n_tokens, out, out_size,
1616                                 obj);
1617                         return;
1618                 }
1619
1620                 if ((n_tokens >= 3) &&
1621                         (strcmp(tokens[2], "table") == 0)) {
1622                         cmd_pipeline_table_update(tokens, n_tokens, out,
1623                                 out_size, obj);
1624                         return;
1625                 }
1626
1627                 if ((n_tokens >= 3) &&
1628                         (strcmp(tokens[2], "stats") == 0)) {
1629                         cmd_pipeline_stats(tokens, n_tokens, out, out_size,
1630                                 obj);
1631                         return;
1632                 }
1633         }
1634
1635         if (strcmp(tokens[0], "thread") == 0) {
1636                 if ((n_tokens >= 5) &&
1637                         (strcmp(tokens[4], "enable") == 0)) {
1638                         cmd_thread_pipeline_enable(tokens, n_tokens,
1639                                 out, out_size, obj);
1640                         return;
1641                 }
1642
1643                 if ((n_tokens >= 5) &&
1644                         (strcmp(tokens[4], "disable") == 0)) {
1645                         cmd_thread_pipeline_disable(tokens, n_tokens,
1646                                 out, out_size, obj);
1647                         return;
1648                 }
1649         }
1650
1651         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
1652 }
1653
1654 int
1655 cli_script_process(const char *file_name,
1656         size_t msg_in_len_max,
1657         size_t msg_out_len_max,
1658         void *obj)
1659 {
1660         char *msg_in = NULL, *msg_out = NULL;
1661         FILE *f = NULL;
1662
1663         /* Check input arguments */
1664         if ((file_name == NULL) ||
1665                 (strlen(file_name) == 0) ||
1666                 (msg_in_len_max == 0) ||
1667                 (msg_out_len_max == 0))
1668                 return -EINVAL;
1669
1670         msg_in = malloc(msg_in_len_max + 1);
1671         msg_out = malloc(msg_out_len_max + 1);
1672         if ((msg_in == NULL) ||
1673                 (msg_out == NULL)) {
1674                 free(msg_out);
1675                 free(msg_in);
1676                 return -ENOMEM;
1677         }
1678
1679         /* Open input file */
1680         f = fopen(file_name, "r");
1681         if (f == NULL) {
1682                 free(msg_out);
1683                 free(msg_in);
1684                 return -EIO;
1685         }
1686
1687         /* Read file */
1688         for ( ; ; ) {
1689                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
1690                         break;
1691
1692                 printf("%s", msg_in);
1693                 msg_out[0] = 0;
1694
1695                 cli_process(msg_in,
1696                         msg_out,
1697                         msg_out_len_max,
1698                         obj);
1699
1700                 if (strlen(msg_out))
1701                         printf("%s", msg_out);
1702         }
1703
1704         /* Close file */
1705         fclose(f);
1706         free(msg_out);
1707         free(msg_in);
1708         return 0;
1709 }