pipeline: add register 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_stats_help[] =
1359 "pipeline <pipeline_name> stats\n";
1360
1361 static void
1362 cmd_pipeline_stats(char **tokens,
1363         uint32_t n_tokens,
1364         char *out,
1365         size_t out_size,
1366         void *obj)
1367 {
1368         struct rte_swx_ctl_pipeline_info info;
1369         struct pipeline *p;
1370         uint32_t i;
1371         int status;
1372
1373         if (n_tokens != 3) {
1374                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1375                 return;
1376         }
1377
1378         p = pipeline_find(obj, tokens[1]);
1379         if (!p || !p->ctl) {
1380                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1381                 return;
1382         }
1383
1384         if (strcmp(tokens[2], "stats")) {
1385                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1386                 return;
1387         }
1388
1389         status = rte_swx_ctl_pipeline_info_get(p->p, &info);
1390         if (status) {
1391                 snprintf(out, out_size, "Pipeline info get error.");
1392                 return;
1393         }
1394
1395         snprintf(out, out_size, "Input ports:\n");
1396         out_size -= strlen(out);
1397         out += strlen(out);
1398
1399         for (i = 0; i < info.n_ports_in; i++) {
1400                 struct rte_swx_port_in_stats stats;
1401
1402                 rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
1403
1404                 snprintf(out, out_size, "\tPort %u:"
1405                         " packets %" PRIu64
1406                         " bytes %" PRIu64
1407                         " empty %" PRIu64 "\n",
1408                         i, stats.n_pkts, stats.n_bytes, stats.n_empty);
1409                 out_size -= strlen(out);
1410                 out += strlen(out);
1411         }
1412
1413         snprintf(out, out_size, "Output ports:\n");
1414         out_size -= strlen(out);
1415         out += strlen(out);
1416
1417         for (i = 0; i < info.n_ports_out; i++) {
1418                 struct rte_swx_port_out_stats stats;
1419
1420                 rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
1421
1422                 snprintf(out, out_size, "\tPort %u:"
1423                         " packets %" PRIu64
1424                         " bytes %" PRIu64 "\n",
1425                         i, stats.n_pkts, stats.n_bytes);
1426                 out_size -= strlen(out);
1427                 out += strlen(out);
1428         }
1429 }
1430
1431 static const char cmd_thread_pipeline_enable_help[] =
1432 "thread <thread_id> pipeline <pipeline_name> enable\n";
1433
1434 static void
1435 cmd_thread_pipeline_enable(char **tokens,
1436         uint32_t n_tokens,
1437         char *out,
1438         size_t out_size,
1439         void *obj)
1440 {
1441         char *pipeline_name;
1442         struct pipeline *p;
1443         uint32_t thread_id;
1444         int status;
1445
1446         if (n_tokens != 5) {
1447                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1448                 return;
1449         }
1450
1451         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
1452                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
1453                 return;
1454         }
1455
1456         if (strcmp(tokens[2], "pipeline") != 0) {
1457                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
1458                 return;
1459         }
1460
1461         pipeline_name = tokens[3];
1462         p = pipeline_find(obj, pipeline_name);
1463         if (!p || !p->ctl) {
1464                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1465                 return;
1466         }
1467
1468         if (strcmp(tokens[4], "enable") != 0) {
1469                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
1470                 return;
1471         }
1472
1473         status = thread_pipeline_enable(thread_id, obj, pipeline_name);
1474         if (status) {
1475                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
1476                 return;
1477         }
1478 }
1479
1480 static const char cmd_thread_pipeline_disable_help[] =
1481 "thread <thread_id> pipeline <pipeline_name> disable\n";
1482
1483 static void
1484 cmd_thread_pipeline_disable(char **tokens,
1485         uint32_t n_tokens,
1486         char *out,
1487         size_t out_size,
1488         void *obj)
1489 {
1490         struct pipeline *p;
1491         char *pipeline_name;
1492         uint32_t thread_id;
1493         int status;
1494
1495         if (n_tokens != 5) {
1496                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1497                 return;
1498         }
1499
1500         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
1501                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
1502                 return;
1503         }
1504
1505         if (strcmp(tokens[2], "pipeline") != 0) {
1506                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
1507                 return;
1508         }
1509
1510         pipeline_name = tokens[3];
1511         p = pipeline_find(obj, pipeline_name);
1512         if (!p || !p->ctl) {
1513                 snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1514                 return;
1515         }
1516
1517         if (strcmp(tokens[4], "disable") != 0) {
1518                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
1519                 return;
1520         }
1521
1522         status = thread_pipeline_disable(thread_id, obj, pipeline_name);
1523         if (status) {
1524                 snprintf(out, out_size, MSG_CMD_FAIL,
1525                         "thread pipeline disable");
1526                 return;
1527         }
1528 }
1529
1530 static void
1531 cmd_help(char **tokens,
1532          uint32_t n_tokens,
1533          char *out,
1534          size_t out_size,
1535          void *arg __rte_unused)
1536 {
1537         tokens++;
1538         n_tokens--;
1539
1540         if (n_tokens == 0) {
1541                 snprintf(out, out_size,
1542                         "Type 'help <command>' for command details.\n\n"
1543                         "List of commands:\n"
1544                         "\tmempool\n"
1545                         "\tlink\n"
1546                         "\ttap\n"
1547                         "\tpipeline create\n"
1548                         "\tpipeline port in\n"
1549                         "\tpipeline port out\n"
1550                         "\tpipeline build\n"
1551                         "\tpipeline table update\n"
1552                         "\tpipeline regrd\n"
1553                         "\tpipeline regwr\n"
1554                         "\tpipeline stats\n"
1555                         "\tthread pipeline enable\n"
1556                         "\tthread pipeline disable\n\n");
1557                 return;
1558         }
1559
1560         if (strcmp(tokens[0], "mempool") == 0) {
1561                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
1562                 return;
1563         }
1564
1565         if (strcmp(tokens[0], "link") == 0) {
1566                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
1567                 return;
1568         }
1569
1570         if (strcmp(tokens[0], "ring") == 0) {
1571                 snprintf(out, out_size, "\n%s\n", cmd_ring_help);
1572                 return;
1573         }
1574
1575         if (strcmp(tokens[0], "tap") == 0) {
1576                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
1577                 return;
1578         }
1579
1580         if ((strcmp(tokens[0], "pipeline") == 0) &&
1581                 (n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
1582                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
1583                 return;
1584         }
1585
1586         if ((strcmp(tokens[0], "pipeline") == 0) &&
1587                 (n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
1588                 if (strcmp(tokens[2], "in") == 0) {
1589                         snprintf(out, out_size, "\n%s\n",
1590                                 cmd_pipeline_port_in_help);
1591                         return;
1592                 }
1593
1594                 if (strcmp(tokens[2], "out") == 0) {
1595                         snprintf(out, out_size, "\n%s\n",
1596                                 cmd_pipeline_port_out_help);
1597                         return;
1598                 }
1599         }
1600
1601         if ((strcmp(tokens[0], "pipeline") == 0) &&
1602                 (n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
1603                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
1604                 return;
1605         }
1606
1607         if ((strcmp(tokens[0], "pipeline") == 0) &&
1608                 (n_tokens == 3) &&
1609                 (strcmp(tokens[1], "table") == 0) &&
1610                 (strcmp(tokens[2], "update") == 0)) {
1611                 snprintf(out, out_size, "\n%s\n",
1612                         cmd_pipeline_table_update_help);
1613                 return;
1614         }
1615
1616         if ((strcmp(tokens[0], "pipeline") == 0) &&
1617                 (n_tokens == 2) && (strcmp(tokens[1], "regrd") == 0)) {
1618                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regrd_help);
1619                 return;
1620         }
1621
1622         if ((strcmp(tokens[0], "pipeline") == 0) &&
1623                 (n_tokens == 2) && (strcmp(tokens[1], "regwr") == 0)) {
1624                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_regwr_help);
1625                 return;
1626         }
1627
1628         if ((strcmp(tokens[0], "pipeline") == 0) &&
1629                 (n_tokens == 2) && (strcmp(tokens[1], "stats") == 0)) {
1630                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_stats_help);
1631                 return;
1632         }
1633
1634         if ((n_tokens == 3) &&
1635                 (strcmp(tokens[0], "thread") == 0) &&
1636                 (strcmp(tokens[1], "pipeline") == 0)) {
1637                 if (strcmp(tokens[2], "enable") == 0) {
1638                         snprintf(out, out_size, "\n%s\n",
1639                                 cmd_thread_pipeline_enable_help);
1640                         return;
1641                 }
1642
1643                 if (strcmp(tokens[2], "disable") == 0) {
1644                         snprintf(out, out_size, "\n%s\n",
1645                                 cmd_thread_pipeline_disable_help);
1646                         return;
1647                 }
1648         }
1649
1650         snprintf(out, out_size, "Invalid command\n");
1651 }
1652
1653 void
1654 cli_process(char *in, char *out, size_t out_size, void *obj)
1655 {
1656         char *tokens[CMD_MAX_TOKENS];
1657         uint32_t n_tokens = RTE_DIM(tokens);
1658         int status;
1659
1660         if (is_comment(in))
1661                 return;
1662
1663         status = parse_tokenize_string(in, tokens, &n_tokens);
1664         if (status) {
1665                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
1666                 return;
1667         }
1668
1669         if (n_tokens == 0)
1670                 return;
1671
1672         if (strcmp(tokens[0], "help") == 0) {
1673                 cmd_help(tokens, n_tokens, out, out_size, obj);
1674                 return;
1675         }
1676
1677         if (strcmp(tokens[0], "mempool") == 0) {
1678                 cmd_mempool(tokens, n_tokens, out, out_size, obj);
1679                 return;
1680         }
1681
1682         if (strcmp(tokens[0], "link") == 0) {
1683                 if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
1684                         cmd_link_show(tokens, n_tokens, out, out_size, obj);
1685                         return;
1686                 }
1687
1688                 cmd_link(tokens, n_tokens, out, out_size, obj);
1689                 return;
1690         }
1691
1692         if (strcmp(tokens[0], "ring") == 0) {
1693                 cmd_ring(tokens, n_tokens, out, out_size, obj);
1694                 return;
1695         }
1696
1697         if (strcmp(tokens[0], "tap") == 0) {
1698                 cmd_tap(tokens, n_tokens, out, out_size, obj);
1699                 return;
1700         }
1701
1702         if (strcmp(tokens[0], "pipeline") == 0) {
1703                 if ((n_tokens >= 3) &&
1704                         (strcmp(tokens[2], "create") == 0)) {
1705                         cmd_pipeline_create(tokens, n_tokens, out, out_size,
1706                                 obj);
1707                         return;
1708                 }
1709
1710                 if ((n_tokens >= 4) &&
1711                         (strcmp(tokens[2], "port") == 0) &&
1712                         (strcmp(tokens[3], "in") == 0)) {
1713                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
1714                                 obj);
1715                         return;
1716                 }
1717
1718                 if ((n_tokens >= 4) &&
1719                         (strcmp(tokens[2], "port") == 0) &&
1720                         (strcmp(tokens[3], "out") == 0)) {
1721                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
1722                                 obj);
1723                         return;
1724                 }
1725
1726                 if ((n_tokens >= 3) &&
1727                         (strcmp(tokens[2], "build") == 0)) {
1728                         cmd_pipeline_build(tokens, n_tokens, out, out_size,
1729                                 obj);
1730                         return;
1731                 }
1732
1733                 if ((n_tokens >= 3) &&
1734                         (strcmp(tokens[2], "table") == 0)) {
1735                         cmd_pipeline_table_update(tokens, n_tokens, out,
1736                                 out_size, obj);
1737                         return;
1738                 }
1739
1740                 if ((n_tokens >= 3) &&
1741                         (strcmp(tokens[2], "regrd") == 0)) {
1742                         cmd_pipeline_regrd(tokens, n_tokens, out, out_size, obj);
1743                         return;
1744                 }
1745
1746                 if ((n_tokens >= 3) &&
1747                         (strcmp(tokens[2], "regwr") == 0)) {
1748                         cmd_pipeline_regwr(tokens, n_tokens, out, out_size, obj);
1749                         return;
1750                 }
1751
1752                 if ((n_tokens >= 3) &&
1753                         (strcmp(tokens[2], "stats") == 0)) {
1754                         cmd_pipeline_stats(tokens, n_tokens, out, out_size,
1755                                 obj);
1756                         return;
1757                 }
1758         }
1759
1760         if (strcmp(tokens[0], "thread") == 0) {
1761                 if ((n_tokens >= 5) &&
1762                         (strcmp(tokens[4], "enable") == 0)) {
1763                         cmd_thread_pipeline_enable(tokens, n_tokens,
1764                                 out, out_size, obj);
1765                         return;
1766                 }
1767
1768                 if ((n_tokens >= 5) &&
1769                         (strcmp(tokens[4], "disable") == 0)) {
1770                         cmd_thread_pipeline_disable(tokens, n_tokens,
1771                                 out, out_size, obj);
1772                         return;
1773                 }
1774         }
1775
1776         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
1777 }
1778
1779 int
1780 cli_script_process(const char *file_name,
1781         size_t msg_in_len_max,
1782         size_t msg_out_len_max,
1783         void *obj)
1784 {
1785         char *msg_in = NULL, *msg_out = NULL;
1786         FILE *f = NULL;
1787
1788         /* Check input arguments */
1789         if ((file_name == NULL) ||
1790                 (strlen(file_name) == 0) ||
1791                 (msg_in_len_max == 0) ||
1792                 (msg_out_len_max == 0))
1793                 return -EINVAL;
1794
1795         msg_in = malloc(msg_in_len_max + 1);
1796         msg_out = malloc(msg_out_len_max + 1);
1797         if ((msg_in == NULL) ||
1798                 (msg_out == NULL)) {
1799                 free(msg_out);
1800                 free(msg_in);
1801                 return -ENOMEM;
1802         }
1803
1804         /* Open input file */
1805         f = fopen(file_name, "r");
1806         if (f == NULL) {
1807                 free(msg_out);
1808                 free(msg_in);
1809                 return -EIO;
1810         }
1811
1812         /* Read file */
1813         for ( ; ; ) {
1814                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
1815                         break;
1816
1817                 printf("%s", msg_in);
1818                 msg_out[0] = 0;
1819
1820                 cli_process(msg_in,
1821                         msg_out,
1822                         msg_out_len_max,
1823                         obj);
1824
1825                 if (strlen(msg_out))
1826                         printf("%s", msg_out);
1827         }
1828
1829         /* Close file */
1830         fclose(f);
1831         free(msg_out);
1832         free(msg_in);
1833         return 0;
1834 }