770b3bcd44e0d97bbd8ed4ce31d42f29db4afe00
[dpdk.git] / examples / ip_pipeline / cli.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 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_cycles.h>
12 #include <rte_ethdev.h>
13
14 #include "cli.h"
15
16 #include "cryptodev.h"
17 #include "kni.h"
18 #include "link.h"
19 #include "mempool.h"
20 #include "parser.h"
21 #include "pipeline.h"
22 #include "swq.h"
23 #include "tap.h"
24 #include "thread.h"
25 #include "tmgr.h"
26
27 #ifndef CMD_MAX_TOKENS
28 #define CMD_MAX_TOKENS     256
29 #endif
30
31 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
32 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
33 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
34 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
35 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
36 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
37 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
38 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
39 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
40 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
41 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
42
43 static int
44 is_comment(char *in)
45 {
46         if ((strlen(in) && index("!#%;", in[0])) ||
47                 (strncmp(in, "//", 2) == 0) ||
48                 (strncmp(in, "--", 2) == 0))
49                 return 1;
50
51         return 0;
52 }
53
54 static const char cmd_mempool_help[] =
55 "mempool <mempool_name>\n"
56 "   buffer <buffer_size>\n"
57 "   pool <pool_size>\n"
58 "   cache <cache_size>\n"
59 "   cpu <cpu_id>\n";
60
61 static void
62 cmd_mempool(char **tokens,
63         uint32_t n_tokens,
64         char *out,
65         size_t out_size)
66 {
67         struct mempool_params p;
68         char *name;
69         struct mempool *mempool;
70
71         if (n_tokens != 10) {
72                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
73                 return;
74         }
75
76         name = tokens[1];
77
78         if (strcmp(tokens[2], "buffer") != 0) {
79                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
80                 return;
81         }
82
83         if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
84                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
85                 return;
86         }
87
88         if (strcmp(tokens[4], "pool") != 0) {
89                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
90                 return;
91         }
92
93         if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
94                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
95                 return;
96         }
97
98         if (strcmp(tokens[6], "cache") != 0) {
99                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
100                 return;
101         }
102
103         if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
104                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
105                 return;
106         }
107
108         if (strcmp(tokens[8], "cpu") != 0) {
109                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
110                 return;
111         }
112
113         if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
114                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
115                 return;
116         }
117
118         mempool = mempool_create(name, &p);
119         if (mempool == NULL) {
120                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
121                 return;
122         }
123 }
124
125 static const char cmd_link_help[] =
126 "link <link_name>\n"
127 "   dev <device_name> | port <port_id>\n"
128 "   rxq <n_queues> <queue_size> <mempool_name>\n"
129 "   txq <n_queues> <queue_size>\n"
130 "   promiscuous on | off\n"
131 "   [rss <qid_0> ... <qid_n>]\n";
132
133 static void
134 cmd_link(char **tokens,
135         uint32_t n_tokens,
136         char *out,
137         size_t out_size)
138 {
139         struct link_params p;
140         struct link_params_rss rss;
141         struct link *link;
142         char *name;
143
144         memset(&p, 0, sizeof(p));
145
146         if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
147                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
148                 return;
149         }
150         name = tokens[1];
151
152         if (strcmp(tokens[2], "dev") == 0)
153                 p.dev_name = tokens[3];
154         else if (strcmp(tokens[2], "port") == 0) {
155                 p.dev_name = NULL;
156
157                 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
158                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
159                         return;
160                 }
161         } else {
162                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
163                 return;
164         }
165
166         if (strcmp(tokens[4], "rxq") != 0) {
167                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
168                 return;
169         }
170
171         if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
172                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
173                 return;
174         }
175         if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
176                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
177                 return;
178         }
179
180         p.rx.mempool_name = tokens[7];
181
182         if (strcmp(tokens[8], "txq") != 0) {
183                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
184                 return;
185         }
186
187         if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
188                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
189                 return;
190         }
191
192         if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
193                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
194                 return;
195         }
196
197         if (strcmp(tokens[11], "promiscuous") != 0) {
198                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
199                 return;
200         }
201
202         if (strcmp(tokens[12], "on") == 0)
203                 p.promiscuous = 1;
204         else if (strcmp(tokens[12], "off") == 0)
205                 p.promiscuous = 0;
206         else {
207                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
208                 return;
209         }
210
211         /* RSS */
212         p.rx.rss = NULL;
213         if (n_tokens > 13) {
214                 uint32_t queue_id, i;
215
216                 if (strcmp(tokens[13], "rss") != 0) {
217                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
218                         return;
219                 }
220
221                 p.rx.rss = &rss;
222
223                 rss.n_queues = 0;
224                 for (i = 14; i < n_tokens; i++) {
225                         if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
226                                 snprintf(out, out_size, MSG_ARG_INVALID,
227                                         "queue_id");
228                                 return;
229                         }
230
231                         rss.queue_id[rss.n_queues] = queue_id;
232                         rss.n_queues++;
233                 }
234         }
235
236         link = link_create(name, &p);
237         if (link == NULL) {
238                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
239                 return;
240         }
241 }
242
243 /* Print the link stats and info */
244 static void
245 print_link_info(struct link *link, char *out, size_t out_size)
246 {
247         struct rte_eth_stats stats;
248         struct rte_ether_addr mac_addr;
249         struct rte_eth_link eth_link;
250         uint16_t mtu;
251
252         memset(&stats, 0, sizeof(stats));
253         rte_eth_stats_get(link->port_id, &stats);
254
255         rte_eth_macaddr_get(link->port_id, &mac_addr);
256         rte_eth_link_get(link->port_id, &eth_link);
257         rte_eth_dev_get_mtu(link->port_id, &mtu);
258
259         snprintf(out, out_size,
260                 "\n"
261                 "%s: flags=<%s> mtu %u\n"
262                 "\tether %02X:%02X:%02X:%02X:%02X:%02X rxqueues %u txqueues %u\n"
263                 "\tport# %u  speed %u Mbps\n"
264                 "\tRX packets %" PRIu64"  bytes %" PRIu64"\n"
265                 "\tRX errors %" PRIu64"  missed %" PRIu64"  no-mbuf %" PRIu64"\n"
266                 "\tTX packets %" PRIu64"  bytes %" PRIu64"\n"
267                 "\tTX errors %" PRIu64"\n",
268                 link->name,
269                 eth_link.link_status == 0 ? "DOWN" : "UP",
270                 mtu,
271                 mac_addr.addr_bytes[0], mac_addr.addr_bytes[1],
272                 mac_addr.addr_bytes[2], mac_addr.addr_bytes[3],
273                 mac_addr.addr_bytes[4], mac_addr.addr_bytes[5],
274                 link->n_rxq,
275                 link->n_txq,
276                 link->port_id,
277                 eth_link.link_speed,
278                 stats.ipackets,
279                 stats.ibytes,
280                 stats.ierrors,
281                 stats.imissed,
282                 stats.rx_nombuf,
283                 stats.opackets,
284                 stats.obytes,
285                 stats.oerrors);
286 }
287
288 /*
289  * link show [<link_name>]
290  */
291 static void
292 cmd_link_show(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
293 {
294         struct link *link;
295         char *link_name;
296
297         if (n_tokens != 2 && n_tokens != 3) {
298                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
299                 return;
300         }
301
302         if (n_tokens == 2) {
303                 link = link_next(NULL);
304
305                 while (link != NULL) {
306                         out_size = out_size - strlen(out);
307                         out = &out[strlen(out)];
308
309                         print_link_info(link, out, out_size);
310                         link = link_next(link);
311                 }
312         } else {
313                 out_size = out_size - strlen(out);
314                 out = &out[strlen(out)];
315
316                 link_name = tokens[2];
317                 link = link_find(link_name);
318
319                 if (link == NULL) {
320                         snprintf(out, out_size, MSG_ARG_INVALID,
321                                         "Link does not exist");
322                         return;
323                 }
324                 print_link_info(link, out, out_size);
325         }
326 }
327
328 static const char cmd_swq_help[] =
329 "swq <swq_name>\n"
330 "   size <size>\n"
331 "   cpu <cpu_id>\n";
332
333 static void
334 cmd_swq(char **tokens,
335         uint32_t n_tokens,
336         char *out,
337         size_t out_size)
338 {
339         struct swq_params p;
340         char *name;
341         struct swq *swq;
342
343         if (n_tokens != 6) {
344                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
345                 return;
346         }
347
348         name = tokens[1];
349
350         if (strcmp(tokens[2], "size") != 0) {
351                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
352                 return;
353         }
354
355         if (parser_read_uint32(&p.size, tokens[3]) != 0) {
356                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
357                 return;
358         }
359
360         if (strcmp(tokens[4], "cpu") != 0) {
361                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
362                 return;
363         }
364
365         if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
366                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
367                 return;
368         }
369
370         swq = swq_create(name, &p);
371         if (swq == NULL) {
372                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
373                 return;
374         }
375 }
376
377 static const char cmd_tmgr_subport_profile_help[] =
378 "tmgr subport profile\n"
379 "   <tb_rate> <tb_size>\n"
380 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>\n"
381 "   <tc_period>\n";
382
383 static void
384 cmd_tmgr_subport_profile(char **tokens,
385         uint32_t n_tokens,
386         char *out,
387         size_t out_size)
388 {
389         struct rte_sched_subport_params p;
390         int status, i;
391
392         if (n_tokens != 10) {
393                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
394                 return;
395         }
396
397         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
398                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
399                 return;
400         }
401
402         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
403                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
404                 return;
405         }
406
407         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
408                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
409                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
410                         return;
411                 }
412
413         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
414                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
415                 return;
416         }
417
418         status = tmgr_subport_profile_add(&p);
419         if (status != 0) {
420                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
421                 return;
422         }
423 }
424
425 static const char cmd_tmgr_pipe_profile_help[] =
426 "tmgr pipe profile\n"
427 "   <tb_rate> <tb_size>\n"
428 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>\n"
429 "   <tc_period>\n"
430 "   <tc_ov_weight>\n"
431 "   <wrr_weight0..15>\n";
432
433 static void
434 cmd_tmgr_pipe_profile(char **tokens,
435         uint32_t n_tokens,
436         char *out,
437         size_t out_size)
438 {
439         struct rte_sched_pipe_params p;
440         int status, i;
441
442         if (n_tokens != 27) {
443                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
444                 return;
445         }
446
447         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
448                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
449                 return;
450         }
451
452         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
453                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
454                 return;
455         }
456
457         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
458                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
459                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
460                         return;
461                 }
462
463         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
464                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
465                 return;
466         }
467
468 #ifdef RTE_SCHED_SUBPORT_TC_OV
469         if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) {
470                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
471                 return;
472         }
473 #endif
474
475         for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
476                 if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
477                         snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
478                         return;
479                 }
480
481         status = tmgr_pipe_profile_add(&p);
482         if (status != 0) {
483                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
484                 return;
485         }
486 }
487
488 static const char cmd_tmgr_help[] =
489 "tmgr <tmgr_name>\n"
490 "   rate <rate>\n"
491 "   spp <n_subports_per_port>\n"
492 "   pps <n_pipes_per_subport>\n"
493 "   qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>\n"
494 "   fo <frame_overhead>\n"
495 "   mtu <mtu>\n"
496 "   cpu <cpu_id>\n";
497
498 static void
499 cmd_tmgr(char **tokens,
500         uint32_t n_tokens,
501         char *out,
502         size_t out_size)
503 {
504         struct tmgr_port_params p;
505         char *name;
506         struct tmgr_port *tmgr_port;
507         int i;
508
509         if (n_tokens != 19) {
510                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
511                 return;
512         }
513
514         name = tokens[1];
515
516         if (strcmp(tokens[2], "rate") != 0) {
517                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
518                 return;
519         }
520
521         if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
522                 snprintf(out, out_size, MSG_ARG_INVALID, "rate");
523                 return;
524         }
525
526         if (strcmp(tokens[4], "spp") != 0) {
527                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
528                 return;
529         }
530
531         if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
532                 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
533                 return;
534         }
535
536         if (strcmp(tokens[6], "pps") != 0) {
537                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
538                 return;
539         }
540
541         if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
542                 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
543                 return;
544         }
545
546         if (strcmp(tokens[8], "qsize") != 0) {
547                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
548                 return;
549         }
550
551         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
552                 if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
553                         snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
554                         return;
555                 }
556
557         if (strcmp(tokens[13], "fo") != 0) {
558                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
559                 return;
560         }
561
562         if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
563                 snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
564                 return;
565         }
566
567         if (strcmp(tokens[15], "mtu") != 0) {
568                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
569                 return;
570         }
571
572         if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
573                 snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
574                 return;
575         }
576
577         if (strcmp(tokens[17], "cpu") != 0) {
578                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
579                 return;
580         }
581
582         if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
583                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
584                 return;
585         }
586
587         tmgr_port = tmgr_port_create(name, &p);
588         if (tmgr_port == NULL) {
589                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
590                 return;
591         }
592 }
593
594 static const char cmd_tmgr_subport_help[] =
595 "tmgr <tmgr_name> subport <subport_id>\n"
596 "   profile <subport_profile_id>\n";
597
598 static void
599 cmd_tmgr_subport(char **tokens,
600         uint32_t n_tokens,
601         char *out,
602         size_t out_size)
603 {
604         uint32_t subport_id, subport_profile_id;
605         int status;
606         char *name;
607
608         if (n_tokens != 6) {
609                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
610                 return;
611         }
612
613         name = tokens[1];
614
615         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
616                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
617                 return;
618         }
619
620         if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
621                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
622                 return;
623         }
624
625         status = tmgr_subport_config(name, subport_id, subport_profile_id);
626         if (status) {
627                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
628                 return;
629         }
630 }
631
632
633 static const char cmd_tmgr_subport_pipe_help[] =
634 "tmgr <tmgr_name> subport <subport_id> pipe\n"
635 "   from <pipe_id_first> to <pipe_id_last>\n"
636 "   profile <pipe_profile_id>\n";
637
638 static void
639 cmd_tmgr_subport_pipe(char **tokens,
640         uint32_t n_tokens,
641         char *out,
642         size_t out_size)
643 {
644         uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
645         int status;
646         char *name;
647
648         if (n_tokens != 11) {
649                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
650                 return;
651         }
652
653         name = tokens[1];
654
655         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
656                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
657                 return;
658         }
659
660         if (strcmp(tokens[4], "pipe") != 0) {
661                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
662                 return;
663         }
664
665         if (strcmp(tokens[5], "from") != 0) {
666                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
667                 return;
668         }
669
670         if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
671                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
672                 return;
673         }
674
675         if (strcmp(tokens[7], "to") != 0) {
676                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
677                 return;
678         }
679
680         if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
681                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
682                 return;
683         }
684
685         if (strcmp(tokens[9], "profile") != 0) {
686                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
687                 return;
688         }
689
690         if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
691                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
692                 return;
693         }
694
695         status = tmgr_pipe_config(name, subport_id, pipe_id_first,
696                         pipe_id_last, pipe_profile_id);
697         if (status) {
698                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
699                 return;
700         }
701 }
702
703
704 static const char cmd_tap_help[] =
705 "tap <tap_name>\n";
706
707 static void
708 cmd_tap(char **tokens,
709         uint32_t n_tokens,
710         char *out,
711         size_t out_size)
712 {
713         char *name;
714         struct tap *tap;
715
716         if (n_tokens != 2) {
717                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
718                 return;
719         }
720
721         name = tokens[1];
722
723         tap = tap_create(name);
724         if (tap == NULL) {
725                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
726                 return;
727         }
728 }
729
730 static const char cmd_kni_help[] =
731 "kni <kni_name>\n"
732 "   link <link_name>\n"
733 "   mempool <mempool_name>\n"
734 "   [thread <thread_id>]\n";
735
736 static void
737 cmd_kni(char **tokens,
738         uint32_t n_tokens,
739         char *out,
740         size_t out_size)
741 {
742         struct kni_params p;
743         char *name;
744         struct kni *kni;
745
746         memset(&p, 0, sizeof(p));
747         if ((n_tokens != 6) && (n_tokens != 8)) {
748                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
749                 return;
750         }
751
752         name = tokens[1];
753
754         if (strcmp(tokens[2], "link") != 0) {
755                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
756                 return;
757         }
758
759         p.link_name = tokens[3];
760
761         if (strcmp(tokens[4], "mempool") != 0) {
762                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
763                 return;
764         }
765
766         p.mempool_name = tokens[5];
767
768         if (n_tokens == 8) {
769                 if (strcmp(tokens[6], "thread") != 0) {
770                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
771                         return;
772                 }
773
774                 if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
775                         snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
776                         return;
777                 }
778
779                 p.force_bind = 1;
780         } else
781                 p.force_bind = 0;
782
783         kni = kni_create(name, &p);
784         if (kni == NULL) {
785                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
786                 return;
787         }
788 }
789
790 static const char cmd_cryptodev_help[] =
791 "cryptodev <cryptodev_name>\n"
792 "   dev <device_name> | dev_id <device_id>\n"
793 "   queue <n_queues> <queue_size>\n"
794 "   max_sessions <n_sessions>";
795
796 static void
797 cmd_cryptodev(char **tokens,
798         uint32_t n_tokens,
799         char *out,
800         size_t out_size)
801 {
802         struct cryptodev_params params;
803         char *name;
804
805         memset(&params, 0, sizeof(params));
806         if (n_tokens != 9) {
807                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
808                 return;
809         }
810
811         name = tokens[1];
812
813         if (strcmp(tokens[2], "dev") == 0)
814                 params.dev_name = tokens[3];
815         else if (strcmp(tokens[2], "dev_id") == 0) {
816                 if (parser_read_uint32(&params.dev_id, tokens[3]) < 0) {
817                         snprintf(out, out_size, MSG_ARG_INVALID,
818                                 "dev_id");
819                         return;
820                 }
821         } else {
822                 snprintf(out, out_size, MSG_ARG_INVALID,
823                         "cryptodev");
824                 return;
825         }
826
827         if (strcmp(tokens[4], "queue")) {
828                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
829                         "queue");
830                 return;
831         }
832
833         if (parser_read_uint32(&params.n_queues, tokens[5]) < 0) {
834                 snprintf(out, out_size, MSG_ARG_INVALID,
835                         "q");
836                 return;
837         }
838
839         if (parser_read_uint32(&params.queue_size, tokens[6]) < 0) {
840                 snprintf(out, out_size, MSG_ARG_INVALID,
841                         "queue_size");
842                 return;
843         }
844
845         if (strcmp(tokens[7], "max_sessions")) {
846                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
847                         "max_sessions");
848                 return;
849         }
850
851         if (parser_read_uint32(&params.session_pool_size, tokens[8]) < 0) {
852                 snprintf(out, out_size, MSG_ARG_INVALID,
853                         "queue_size");
854                 return;
855         }
856
857         if (cryptodev_create(name, &params) == NULL) {
858                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
859                 return;
860         }
861 }
862
863 static const char cmd_port_in_action_profile_help[] =
864 "port in action profile <profile_name>\n"
865 "   [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]\n"
866 "   [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]\n";
867
868 static void
869 cmd_port_in_action_profile(char **tokens,
870         uint32_t n_tokens,
871         char *out,
872         size_t out_size)
873 {
874         struct port_in_action_profile_params p;
875         struct port_in_action_profile *ap;
876         char *name;
877         uint32_t t0;
878
879         memset(&p, 0, sizeof(p));
880
881         if (n_tokens < 5) {
882                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
883                 return;
884         }
885
886         if (strcmp(tokens[1], "in") != 0) {
887                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
888                 return;
889         }
890
891         if (strcmp(tokens[2], "action") != 0) {
892                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
893                 return;
894         }
895
896         if (strcmp(tokens[3], "profile") != 0) {
897                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
898                 return;
899         }
900
901         name = tokens[4];
902
903         t0 = 5;
904
905         if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) {
906                 uint32_t size;
907
908                 if (n_tokens < t0 + 10) {
909                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
910                         return;
911                 }
912
913                 if (strcmp(tokens[t0 + 1], "match") == 0)
914                         p.fltr.filter_on_match = 1;
915                 else if (strcmp(tokens[t0 + 1], "mismatch") == 0)
916                         p.fltr.filter_on_match = 0;
917                 else {
918                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
919                         return;
920                 }
921
922                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
923                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
924                         return;
925                 }
926
927                 if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) {
928                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
929                         return;
930                 }
931
932                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
933                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
934                         return;
935                 }
936
937                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
938                 if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) ||
939                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
940                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
941                         return;
942                 }
943
944                 if (strcmp(tokens[t0 + 6], "key") != 0) {
945                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
946                         return;
947                 }
948
949                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
950                 if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) ||
951                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
952                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
953                         return;
954                 }
955
956                 if (strcmp(tokens[t0 + 8], "port") != 0) {
957                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
958                         return;
959                 }
960
961                 if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) {
962                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
963                         return;
964                 }
965
966                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
967                 t0 += 10;
968         } /* filter */
969
970         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
971                 uint32_t i;
972
973                 if (n_tokens < t0 + 22) {
974                         snprintf(out, out_size, MSG_ARG_MISMATCH,
975                                 "port in action profile balance");
976                         return;
977                 }
978
979                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
980                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
981                         return;
982                 }
983
984                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
985                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
986                         return;
987                 }
988
989                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
990                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
991                         return;
992                 }
993
994                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
995                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
996                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
997                         return;
998                 }
999
1000                 if (strcmp(tokens[t0 + 5], "port") != 0) {
1001                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1002                         return;
1003                 }
1004
1005                 for (i = 0; i < 16; i++)
1006                         if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) {
1007                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1008                                 return;
1009                         }
1010
1011                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
1012                 t0 += 22;
1013         } /* balance */
1014
1015         if (t0 < n_tokens) {
1016                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1017                 return;
1018         }
1019
1020         ap = port_in_action_profile_create(name, &p);
1021         if (ap == NULL) {
1022                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1023                 return;
1024         }
1025 }
1026
1027
1028 static const char cmd_table_action_profile_help[] =
1029 "table action profile <profile_name>\n"
1030 "   ipv4 | ipv6\n"
1031 "   offset <ip_offset>\n"
1032 "   fwd\n"
1033 "   [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]\n"
1034 "   [meter srtcm | trtcm\n"
1035 "       tc <n_tc>\n"
1036 "       stats none | pkts | bytes | both]\n"
1037 "   [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]\n"
1038 "   [encap ether | vlan | qinq | mpls | pppoe | qinq_pppoe \n"
1039 "       vxlan offset <ether_offset> ipv4 | ipv6 vlan on | off]\n"
1040 "   [nat src | dst\n"
1041 "       proto udp | tcp]\n"
1042 "   [ttl drop | fwd\n"
1043 "       stats none | pkts]\n"
1044 "   [stats pkts | bytes | both]\n"
1045 "   [time]\n"
1046 "   [sym_crypto dev <CRYPTODEV_NAME> offset <op_offset>]\n"
1047 "   [tag]\n"
1048 "   [decap]\n";
1049
1050 static void
1051 cmd_table_action_profile(char **tokens,
1052         uint32_t n_tokens,
1053         char *out,
1054         size_t out_size)
1055 {
1056         struct table_action_profile_params p;
1057         struct table_action_profile *ap;
1058         char *name;
1059         uint32_t t0;
1060
1061         memset(&p, 0, sizeof(p));
1062
1063         if (n_tokens < 8) {
1064                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1065                 return;
1066         }
1067
1068         if (strcmp(tokens[1], "action") != 0) {
1069                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
1070                 return;
1071         }
1072
1073         if (strcmp(tokens[2], "profile") != 0) {
1074                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1075                 return;
1076         }
1077
1078         name = tokens[3];
1079
1080         if (strcmp(tokens[4], "ipv4") == 0)
1081                 p.common.ip_version = 1;
1082         else if (strcmp(tokens[4], "ipv6") == 0)
1083                 p.common.ip_version = 0;
1084         else {
1085                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
1086                 return;
1087         }
1088
1089         if (strcmp(tokens[5], "offset") != 0) {
1090                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1091                 return;
1092         }
1093
1094         if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
1095                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
1096                 return;
1097         }
1098
1099         if (strcmp(tokens[7], "fwd") != 0) {
1100                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
1101                 return;
1102         }
1103
1104         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
1105
1106         t0 = 8;
1107         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
1108                 if (n_tokens < t0 + 7) {
1109                         snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
1110                         return;
1111                 }
1112
1113                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1114                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1115                         return;
1116                 }
1117
1118                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
1119                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1120                         return;
1121                 }
1122
1123                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
1124                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1125                         return;
1126                 }
1127
1128                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
1129                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
1130                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1131                         return;
1132                 }
1133
1134                 if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
1135                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
1136                         return;
1137                 }
1138
1139                 if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) {
1140                         snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
1141                         return;
1142                 }
1143
1144                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
1145                 t0 += 7;
1146         } /* balance */
1147
1148         if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
1149                 if (n_tokens < t0 + 6) {
1150                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1151                                 "table action profile meter");
1152                         return;
1153                 }
1154
1155                 if (strcmp(tokens[t0 + 1], "srtcm") == 0)
1156                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
1157                 else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
1158                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
1159                 else {
1160                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1161                                 "srtcm or trtcm");
1162                         return;
1163                 }
1164
1165                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
1166                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
1167                         return;
1168                 }
1169
1170                 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
1171                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
1172                         return;
1173                 }
1174
1175                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
1176                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1177                         return;
1178                 }
1179
1180                 if (strcmp(tokens[t0 + 5], "none") == 0) {
1181                         p.mtr.n_packets_enabled = 0;
1182                         p.mtr.n_bytes_enabled = 0;
1183                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
1184                         p.mtr.n_packets_enabled = 1;
1185                         p.mtr.n_bytes_enabled = 0;
1186                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
1187                         p.mtr.n_packets_enabled = 0;
1188                         p.mtr.n_bytes_enabled = 1;
1189                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
1190                         p.mtr.n_packets_enabled = 1;
1191                         p.mtr.n_bytes_enabled = 1;
1192                 } else {
1193                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1194                                 "none or pkts or bytes or both");
1195                         return;
1196                 }
1197
1198                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
1199                 t0 += 6;
1200         } /* meter */
1201
1202         if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
1203                 if (n_tokens < t0 + 5) {
1204                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1205                                 "table action profile tm");
1206                         return;
1207                 }
1208
1209                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
1210                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
1211                         return;
1212                 }
1213
1214                 if (parser_read_uint32(&p.tm.n_subports_per_port,
1215                         tokens[t0 + 2]) != 0) {
1216                         snprintf(out, out_size, MSG_ARG_INVALID,
1217                                 "n_subports_per_port");
1218                         return;
1219                 }
1220
1221                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
1222                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1223                         return;
1224                 }
1225
1226                 if (parser_read_uint32(&p.tm.n_pipes_per_subport,
1227                         tokens[t0 + 4]) != 0) {
1228                         snprintf(out, out_size, MSG_ARG_INVALID,
1229                                 "n_pipes_per_subport");
1230                         return;
1231                 }
1232
1233                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1234                 t0 += 5;
1235         } /* tm */
1236
1237         if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
1238                 uint32_t n_extra_tokens = 0;
1239
1240                 if (n_tokens < t0 + 2) {
1241                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1242                                 "action profile encap");
1243                         return;
1244                 }
1245
1246                 if (strcmp(tokens[t0 + 1], "ether") == 0)
1247                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1248                 else if (strcmp(tokens[t0 + 1], "vlan") == 0)
1249                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1250                 else if (strcmp(tokens[t0 + 1], "qinq") == 0)
1251                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1252                 else if (strcmp(tokens[t0 + 1], "mpls") == 0)
1253                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1254                 else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
1255                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1256                 else if (strcmp(tokens[t0 + 1], "vxlan") == 0) {
1257                         if (n_tokens < t0 + 2 + 5) {
1258                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1259                                         "action profile encap vxlan");
1260                                 return;
1261                         }
1262
1263                         if (strcmp(tokens[t0 + 2], "offset") != 0) {
1264                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1265                                         "vxlan: offset");
1266                                 return;
1267                         }
1268
1269                         if (parser_read_uint32(&p.encap.vxlan.data_offset,
1270                                 tokens[t0 + 2 + 1]) != 0) {
1271                                 snprintf(out, out_size, MSG_ARG_INVALID,
1272                                         "vxlan: ether_offset");
1273                                 return;
1274                         }
1275
1276                         if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0)
1277                                 p.encap.vxlan.ip_version = 1;
1278                         else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0)
1279                                 p.encap.vxlan.ip_version = 0;
1280                         else {
1281                                 snprintf(out, out_size, MSG_ARG_INVALID,
1282                                         "vxlan: ipv4 or ipv6");
1283                                 return;
1284                         }
1285
1286                         if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) {
1287                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1288                                         "vxlan: vlan");
1289                                 return;
1290                         }
1291
1292                         if (strcmp(tokens[t0 + 2 + 4], "on") == 0)
1293                                 p.encap.vxlan.vlan = 1;
1294                         else if (strcmp(tokens[t0 + 2 + 4], "off") == 0)
1295                                 p.encap.vxlan.vlan = 0;
1296                         else {
1297                                 snprintf(out, out_size, MSG_ARG_INVALID,
1298                                         "vxlan: on or off");
1299                                 return;
1300                         }
1301
1302                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN;
1303                         n_extra_tokens = 5;
1304                 } else if (strcmp(tokens[t0 + 1], "qinq_pppoe") == 0)
1305                         p.encap.encap_mask =
1306                                 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ_PPPOE;
1307                 else {
1308                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1309                         return;
1310                 }
1311
1312                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1313                 t0 += 2 + n_extra_tokens;
1314         } /* encap */
1315
1316         if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
1317                 if (n_tokens < t0 + 4) {
1318                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1319                                 "table action profile nat");
1320                         return;
1321                 }
1322
1323                 if (strcmp(tokens[t0 + 1], "src") == 0)
1324                         p.nat.source_nat = 1;
1325                 else if (strcmp(tokens[t0 + 1], "dst") == 0)
1326                         p.nat.source_nat = 0;
1327                 else {
1328                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1329                                 "src or dst");
1330                         return;
1331                 }
1332
1333                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
1334                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1335                         return;
1336                 }
1337
1338                 if (strcmp(tokens[t0 + 3], "tcp") == 0)
1339                         p.nat.proto = 0x06;
1340                 else if (strcmp(tokens[t0 + 3], "udp") == 0)
1341                         p.nat.proto = 0x11;
1342                 else {
1343                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1344                                 "tcp or udp");
1345                         return;
1346                 }
1347
1348                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1349                 t0 += 4;
1350         } /* nat */
1351
1352         if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
1353                 if (n_tokens < t0 + 4) {
1354                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1355                                 "table action profile ttl");
1356                         return;
1357                 }
1358
1359                 if (strcmp(tokens[t0 + 1], "drop") == 0)
1360                         p.ttl.drop = 1;
1361                 else if (strcmp(tokens[t0 + 1], "fwd") == 0)
1362                         p.ttl.drop = 0;
1363                 else {
1364                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1365                                 "drop or fwd");
1366                         return;
1367                 }
1368
1369                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
1370                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1371                         return;
1372                 }
1373
1374                 if (strcmp(tokens[t0 + 3], "none") == 0)
1375                         p.ttl.n_packets_enabled = 0;
1376                 else if (strcmp(tokens[t0 + 3], "pkts") == 0)
1377                         p.ttl.n_packets_enabled = 1;
1378                 else {
1379                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1380                                 "none or pkts");
1381                         return;
1382                 }
1383
1384                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1385                 t0 += 4;
1386         } /* ttl */
1387
1388         if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
1389                 if (n_tokens < t0 + 2) {
1390                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1391                                 "table action profile stats");
1392                         return;
1393                 }
1394
1395                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1396                         p.stats.n_packets_enabled = 1;
1397                         p.stats.n_bytes_enabled = 0;
1398                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1399                         p.stats.n_packets_enabled = 0;
1400                         p.stats.n_bytes_enabled = 1;
1401                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
1402                         p.stats.n_packets_enabled = 1;
1403                         p.stats.n_bytes_enabled = 1;
1404                 } else {
1405                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1406                                 "pkts or bytes or both");
1407                         return;
1408                 }
1409
1410                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1411                 t0 += 2;
1412         } /* stats */
1413
1414         if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
1415                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1416                 t0 += 1;
1417         } /* time */
1418
1419         if ((t0 < n_tokens) && (strcmp(tokens[t0], "sym_crypto") == 0)) {
1420                 struct cryptodev *cryptodev;
1421
1422                 if (n_tokens < t0 + 5 ||
1423                                 strcmp(tokens[t0 + 1], "dev") ||
1424                                 strcmp(tokens[t0 + 3], "offset")) {
1425                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1426                                 "table action profile sym_crypto");
1427                         return;
1428                 }
1429
1430                 cryptodev = cryptodev_find(tokens[t0 + 2]);
1431                 if (cryptodev == NULL) {
1432                         snprintf(out, out_size, MSG_ARG_INVALID,
1433                                 "table action profile sym_crypto");
1434                         return;
1435                 }
1436
1437                 p.sym_crypto.cryptodev_id = cryptodev->dev_id;
1438
1439                 if (parser_read_uint32(&p.sym_crypto.op_offset,
1440                                 tokens[t0 + 4]) != 0) {
1441                         snprintf(out, out_size, MSG_ARG_INVALID,
1442                                         "table action profile sym_crypto");
1443                         return;
1444                 }
1445
1446                 p.sym_crypto.mp_create = cryptodev->mp_create;
1447                 p.sym_crypto.mp_init = cryptodev->mp_init;
1448
1449                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_SYM_CRYPTO;
1450
1451                 t0 += 5;
1452         } /* sym_crypto */
1453
1454         if ((t0 < n_tokens) && (strcmp(tokens[t0], "tag") == 0)) {
1455                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TAG;
1456                 t0 += 1;
1457         } /* tag */
1458
1459         if ((t0 < n_tokens) && (strcmp(tokens[t0], "decap") == 0)) {
1460                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_DECAP;
1461                 t0 += 1;
1462         } /* decap */
1463
1464         if (t0 < n_tokens) {
1465                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1466                 return;
1467         }
1468
1469         ap = table_action_profile_create(name, &p);
1470         if (ap == NULL) {
1471                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1472                 return;
1473         }
1474 }
1475
1476 static const char cmd_pipeline_help[] =
1477 "pipeline <pipeline_name>\n"
1478 "   period <timer_period_ms>\n"
1479 "   offset_port_id <offset_port_id>\n"
1480 "   cpu <cpu_id>\n";
1481
1482 static void
1483 cmd_pipeline(char **tokens,
1484         uint32_t n_tokens,
1485         char *out,
1486         size_t out_size)
1487 {
1488         struct pipeline_params p;
1489         char *name;
1490         struct pipeline *pipeline;
1491
1492         if (n_tokens != 8) {
1493                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1494                 return;
1495         }
1496
1497         name = tokens[1];
1498
1499         if (strcmp(tokens[2], "period") != 0) {
1500                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
1501                 return;
1502         }
1503
1504         if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
1505                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
1506                 return;
1507         }
1508
1509         if (strcmp(tokens[4], "offset_port_id") != 0) {
1510                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
1511                 return;
1512         }
1513
1514         if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
1515                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
1516                 return;
1517         }
1518
1519         if (strcmp(tokens[6], "cpu") != 0) {
1520                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
1521                 return;
1522         }
1523
1524         if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
1525                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
1526                 return;
1527         }
1528
1529         pipeline = pipeline_create(name, &p);
1530         if (pipeline == NULL) {
1531                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1532                 return;
1533         }
1534 }
1535
1536 static const char cmd_pipeline_port_in_help[] =
1537 "pipeline <pipeline_name> port in\n"
1538 "   bsz <burst_size>\n"
1539 "   link <link_name> rxq <queue_id>\n"
1540 "   | swq <swq_name>\n"
1541 "   | tmgr <tmgr_name>\n"
1542 "   | tap <tap_name> mempool <mempool_name> mtu <mtu>\n"
1543 "   | kni <kni_name>\n"
1544 "   | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>\n"
1545 "   | cryptodev <cryptodev_name> rxq <queue_id>\n"
1546 "   [action <port_in_action_profile_name>]\n"
1547 "   [disabled]\n";
1548
1549 static void
1550 cmd_pipeline_port_in(char **tokens,
1551         uint32_t n_tokens,
1552         char *out,
1553         size_t out_size)
1554 {
1555         struct port_in_params p;
1556         char *pipeline_name;
1557         uint32_t t0;
1558         int enabled, status;
1559
1560         if (n_tokens < 7) {
1561                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1562                 return;
1563         }
1564
1565         pipeline_name = tokens[1];
1566
1567         if (strcmp(tokens[2], "port") != 0) {
1568                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1569                 return;
1570         }
1571
1572         if (strcmp(tokens[3], "in") != 0) {
1573                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1574                 return;
1575         }
1576
1577         if (strcmp(tokens[4], "bsz") != 0) {
1578                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1579                 return;
1580         }
1581
1582         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1583                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1584                 return;
1585         }
1586
1587         t0 = 6;
1588
1589         if (strcmp(tokens[t0], "link") == 0) {
1590                 if (n_tokens < t0 + 4) {
1591                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1592                                 "pipeline port in link");
1593                         return;
1594                 }
1595
1596                 p.type = PORT_IN_RXQ;
1597
1598                 p.dev_name = tokens[t0 + 1];
1599
1600                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
1601                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
1602                         return;
1603                 }
1604
1605                 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1606                         snprintf(out, out_size, MSG_ARG_INVALID,
1607                                 "queue_id");
1608                         return;
1609                 }
1610                 t0 += 4;
1611         } else if (strcmp(tokens[t0], "swq") == 0) {
1612                 if (n_tokens < t0 + 2) {
1613                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1614                                 "pipeline port in swq");
1615                         return;
1616                 }
1617
1618                 p.type = PORT_IN_SWQ;
1619
1620                 p.dev_name = tokens[t0 + 1];
1621
1622                 t0 += 2;
1623         } else if (strcmp(tokens[t0], "tmgr") == 0) {
1624                 if (n_tokens < t0 + 2) {
1625                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1626                                 "pipeline port in tmgr");
1627                         return;
1628                 }
1629
1630                 p.type = PORT_IN_TMGR;
1631
1632                 p.dev_name = tokens[t0 + 1];
1633
1634                 t0 += 2;
1635         } else if (strcmp(tokens[t0], "tap") == 0) {
1636                 if (n_tokens < t0 + 6) {
1637                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1638                                 "pipeline port in tap");
1639                         return;
1640                 }
1641
1642                 p.type = PORT_IN_TAP;
1643
1644                 p.dev_name = tokens[t0 + 1];
1645
1646                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
1647                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1648                                 "mempool");
1649                         return;
1650                 }
1651
1652                 p.tap.mempool_name = tokens[t0 + 3];
1653
1654                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
1655                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1656                                 "mtu");
1657                         return;
1658                 }
1659
1660                 if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
1661                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
1662                         return;
1663                 }
1664
1665                 t0 += 6;
1666         } else if (strcmp(tokens[t0], "kni") == 0) {
1667                 if (n_tokens < t0 + 2) {
1668                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1669                                 "pipeline port in kni");
1670                         return;
1671                 }
1672
1673                 p.type = PORT_IN_KNI;
1674
1675                 p.dev_name = tokens[t0 + 1];
1676
1677                 t0 += 2;
1678         } else if (strcmp(tokens[t0], "source") == 0) {
1679                 if (n_tokens < t0 + 6) {
1680                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1681                                 "pipeline port in source");
1682                         return;
1683                 }
1684
1685                 p.type = PORT_IN_SOURCE;
1686
1687                 p.dev_name = NULL;
1688
1689                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
1690                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1691                                 "mempool");
1692                         return;
1693                 }
1694
1695                 p.source.mempool_name = tokens[t0 + 2];
1696
1697                 if (strcmp(tokens[t0 + 3], "file") != 0) {
1698                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1699                                 "file");
1700                         return;
1701                 }
1702
1703                 p.source.file_name = tokens[t0 + 4];
1704
1705                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
1706                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1707                                 "bpp");
1708                         return;
1709                 }
1710
1711                 if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) {
1712                         snprintf(out, out_size, MSG_ARG_INVALID,
1713                                 "n_bytes_per_pkt");
1714                         return;
1715                 }
1716
1717                 t0 += 7;
1718         } else if (strcmp(tokens[t0], "cryptodev") == 0) {
1719                 if (n_tokens < t0 + 3) {
1720                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1721                                 "pipeline port in cryptodev");
1722                         return;
1723                 }
1724
1725                 p.type = PORT_IN_CRYPTODEV;
1726
1727                 p.dev_name = tokens[t0 + 1];
1728                 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1729                         snprintf(out, out_size, MSG_ARG_INVALID,
1730                                 "rxq");
1731                         return;
1732                 }
1733
1734                 p.cryptodev.arg_callback = NULL;
1735                 p.cryptodev.f_callback = NULL;
1736
1737                 t0 += 4;
1738         } else {
1739                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1740                 return;
1741         }
1742
1743         p.action_profile_name = NULL;
1744         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1745                 if (n_tokens < t0 + 2) {
1746                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1747                         return;
1748                 }
1749
1750                 p.action_profile_name = tokens[t0 + 1];
1751
1752                 t0 += 2;
1753         }
1754
1755         enabled = 1;
1756         if ((n_tokens > t0) &&
1757                 (strcmp(tokens[t0], "disabled") == 0)) {
1758                 enabled = 0;
1759
1760                 t0 += 1;
1761         }
1762
1763         if (n_tokens != t0) {
1764                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1765                 return;
1766         }
1767
1768         status = pipeline_port_in_create(pipeline_name,
1769                 &p, enabled);
1770         if (status) {
1771                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1772                 return;
1773         }
1774 }
1775
1776 static const char cmd_pipeline_port_out_help[] =
1777 "pipeline <pipeline_name> port out\n"
1778 "   bsz <burst_size>\n"
1779 "   link <link_name> txq <txq_id>\n"
1780 "   | swq <swq_name>\n"
1781 "   | tmgr <tmgr_name>\n"
1782 "   | tap <tap_name>\n"
1783 "   | kni <kni_name>\n"
1784 "   | sink [file <file_name> pkts <max_n_pkts>]\n"
1785 "   | cryptodev <cryptodev_name> txq <txq_id> offset <crypto_op_offset>\n";
1786
1787 static void
1788 cmd_pipeline_port_out(char **tokens,
1789         uint32_t n_tokens,
1790         char *out,
1791         size_t out_size)
1792 {
1793         struct port_out_params p;
1794         char *pipeline_name;
1795         int status;
1796
1797         memset(&p, 0, sizeof(p));
1798
1799         if (n_tokens < 7) {
1800                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1801                 return;
1802         }
1803
1804         pipeline_name = tokens[1];
1805
1806         if (strcmp(tokens[2], "port") != 0) {
1807                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1808                 return;
1809         }
1810
1811         if (strcmp(tokens[3], "out") != 0) {
1812                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1813                 return;
1814         }
1815
1816         if (strcmp(tokens[4], "bsz") != 0) {
1817                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1818                 return;
1819         }
1820
1821         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1822                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1823                 return;
1824         }
1825
1826         if (strcmp(tokens[6], "link") == 0) {
1827                 if (n_tokens != 10) {
1828                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1829                                 "pipeline port out link");
1830                         return;
1831                 }
1832
1833                 p.type = PORT_OUT_TXQ;
1834
1835                 p.dev_name = tokens[7];
1836
1837                 if (strcmp(tokens[8], "txq") != 0) {
1838                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1839                         return;
1840                 }
1841
1842                 if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
1843                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1844                         return;
1845                 }
1846         } else if (strcmp(tokens[6], "swq") == 0) {
1847                 if (n_tokens != 8) {
1848                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1849                                 "pipeline port out swq");
1850                         return;
1851                 }
1852
1853                 p.type = PORT_OUT_SWQ;
1854
1855                 p.dev_name = tokens[7];
1856         } else if (strcmp(tokens[6], "tmgr") == 0) {
1857                 if (n_tokens != 8) {
1858                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1859                                 "pipeline port out tmgr");
1860                         return;
1861                 }
1862
1863                 p.type = PORT_OUT_TMGR;
1864
1865                 p.dev_name = tokens[7];
1866         } else if (strcmp(tokens[6], "tap") == 0) {
1867                 if (n_tokens != 8) {
1868                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1869                                 "pipeline port out tap");
1870                         return;
1871                 }
1872
1873                 p.type = PORT_OUT_TAP;
1874
1875                 p.dev_name = tokens[7];
1876         } else if (strcmp(tokens[6], "kni") == 0) {
1877                 if (n_tokens != 8) {
1878                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1879                                 "pipeline port out kni");
1880                         return;
1881                 }
1882
1883                 p.type = PORT_OUT_KNI;
1884
1885                 p.dev_name = tokens[7];
1886         } else if (strcmp(tokens[6], "sink") == 0) {
1887                 if ((n_tokens != 7) && (n_tokens != 11)) {
1888                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1889                                 "pipeline port out sink");
1890                         return;
1891                 }
1892
1893                 p.type = PORT_OUT_SINK;
1894
1895                 p.dev_name = NULL;
1896
1897                 if (n_tokens == 7) {
1898                         p.sink.file_name = NULL;
1899                         p.sink.max_n_pkts = 0;
1900                 } else {
1901                         if (strcmp(tokens[7], "file") != 0) {
1902                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1903                                         "file");
1904                                 return;
1905                         }
1906
1907                         p.sink.file_name = tokens[8];
1908
1909                         if (strcmp(tokens[9], "pkts") != 0) {
1910                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1911                                 return;
1912                         }
1913
1914                         if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) {
1915                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1916                                 return;
1917                         }
1918                 }
1919
1920         } else if (strcmp(tokens[6], "cryptodev") == 0) {
1921                 if (n_tokens != 12) {
1922                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1923                                 "pipeline port out cryptodev");
1924                         return;
1925                 }
1926
1927                 p.type = PORT_OUT_CRYPTODEV;
1928
1929                 p.dev_name = tokens[7];
1930
1931                 if (strcmp(tokens[8], "txq")) {
1932                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1933                                 "pipeline port out cryptodev");
1934                         return;
1935                 }
1936
1937                 if (parser_read_uint16(&p.cryptodev.queue_id, tokens[9])
1938                                 != 0) {
1939                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1940                         return;
1941                 }
1942
1943                 if (strcmp(tokens[10], "offset")) {
1944                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1945                                 "pipeline port out cryptodev");
1946                         return;
1947                 }
1948
1949                 if (parser_read_uint32(&p.cryptodev.op_offset, tokens[11])
1950                                 != 0) {
1951                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1952                         return;
1953                 }
1954         } else {
1955                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1956                 return;
1957         }
1958
1959         status = pipeline_port_out_create(pipeline_name, &p);
1960         if (status) {
1961                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1962                 return;
1963         }
1964 }
1965
1966 static const char cmd_pipeline_table_help[] =
1967 "pipeline <pipeline_name> table\n"
1968 "       match\n"
1969 "       acl\n"
1970 "           ipv4 | ipv6\n"
1971 "           offset <ip_header_offset>\n"
1972 "           size <n_rules>\n"
1973 "       | array\n"
1974 "           offset <key_offset>\n"
1975 "           size <n_keys>\n"
1976 "       | hash\n"
1977 "           ext | lru\n"
1978 "           key <key_size>\n"
1979 "           mask <key_mask>\n"
1980 "           offset <key_offset>\n"
1981 "           buckets <n_buckets>\n"
1982 "           size <n_keys>\n"
1983 "       | lpm\n"
1984 "           ipv4 | ipv6\n"
1985 "           offset <ip_header_offset>\n"
1986 "           size <n_rules>\n"
1987 "       | stub\n"
1988 "   [action <table_action_profile_name>]\n";
1989
1990 static void
1991 cmd_pipeline_table(char **tokens,
1992         uint32_t n_tokens,
1993         char *out,
1994         size_t out_size)
1995 {
1996         uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1997         struct table_params p;
1998         char *pipeline_name;
1999         uint32_t t0;
2000         int status;
2001
2002         if (n_tokens < 5) {
2003                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2004                 return;
2005         }
2006
2007         pipeline_name = tokens[1];
2008
2009         if (strcmp(tokens[2], "table") != 0) {
2010                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2011                 return;
2012         }
2013
2014         if (strcmp(tokens[3], "match") != 0) {
2015                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2016                 return;
2017         }
2018
2019         t0 = 4;
2020         if (strcmp(tokens[t0], "acl") == 0) {
2021                 if (n_tokens < t0 + 6) {
2022                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2023                                 "pipeline table acl");
2024                         return;
2025                 }
2026
2027                 p.match_type = TABLE_ACL;
2028
2029                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
2030                         p.match.acl.ip_version = 1;
2031                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
2032                         p.match.acl.ip_version = 0;
2033                 else {
2034                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2035                                 "ipv4 or ipv6");
2036                         return;
2037                 }
2038
2039                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
2040                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2041                         return;
2042                 }
2043
2044                 if (parser_read_uint32(&p.match.acl.ip_header_offset,
2045                         tokens[t0 + 3]) != 0) {
2046                         snprintf(out, out_size, MSG_ARG_INVALID,
2047                                 "ip_header_offset");
2048                         return;
2049                 }
2050
2051                 if (strcmp(tokens[t0 + 4], "size") != 0) {
2052                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2053                         return;
2054                 }
2055
2056                 if (parser_read_uint32(&p.match.acl.n_rules,
2057                         tokens[t0 + 5]) != 0) {
2058                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2059                         return;
2060                 }
2061
2062                 t0 += 6;
2063         } else if (strcmp(tokens[t0], "array") == 0) {
2064                 if (n_tokens < t0 + 5) {
2065                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2066                                 "pipeline table array");
2067                         return;
2068                 }
2069
2070                 p.match_type = TABLE_ARRAY;
2071
2072                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
2073                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2074                         return;
2075                 }
2076
2077                 if (parser_read_uint32(&p.match.array.key_offset,
2078                         tokens[t0 + 2]) != 0) {
2079                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2080                         return;
2081                 }
2082
2083                 if (strcmp(tokens[t0 + 3], "size") != 0) {
2084                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2085                         return;
2086                 }
2087
2088                 if (parser_read_uint32(&p.match.array.n_keys,
2089                         tokens[t0 + 4]) != 0) {
2090                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
2091                         return;
2092                 }
2093
2094                 t0 += 5;
2095         } else if (strcmp(tokens[t0], "hash") == 0) {
2096                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
2097
2098                 if (n_tokens < t0 + 12) {
2099                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2100                                 "pipeline table hash");
2101                         return;
2102                 }
2103
2104                 p.match_type = TABLE_HASH;
2105
2106                 if (strcmp(tokens[t0 + 1], "ext") == 0)
2107                         p.match.hash.extendable_bucket = 1;
2108                 else if (strcmp(tokens[t0 + 1], "lru") == 0)
2109                         p.match.hash.extendable_bucket = 0;
2110                 else {
2111                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2112                                 "ext or lru");
2113                         return;
2114                 }
2115
2116                 if (strcmp(tokens[t0 + 2], "key") != 0) {
2117                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
2118                         return;
2119                 }
2120
2121                 if ((parser_read_uint32(&p.match.hash.key_size,
2122                         tokens[t0 + 3]) != 0) ||
2123                         (p.match.hash.key_size == 0) ||
2124                         (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
2125                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
2126                         return;
2127                 }
2128
2129                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
2130                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
2131                         return;
2132                 }
2133
2134                 if ((parse_hex_string(tokens[t0 + 5],
2135                         key_mask, &key_mask_size) != 0) ||
2136                         (key_mask_size != p.match.hash.key_size)) {
2137                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
2138                         return;
2139                 }
2140                 p.match.hash.key_mask = key_mask;
2141
2142                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
2143                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2144                         return;
2145                 }
2146
2147                 if (parser_read_uint32(&p.match.hash.key_offset,
2148                         tokens[t0 + 7]) != 0) {
2149                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2150                         return;
2151                 }
2152
2153                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
2154                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
2155                         return;
2156                 }
2157
2158                 if (parser_read_uint32(&p.match.hash.n_buckets,
2159                         tokens[t0 + 9]) != 0) {
2160                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
2161                         return;
2162                 }
2163
2164                 if (strcmp(tokens[t0 + 10], "size") != 0) {
2165                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2166                         return;
2167                 }
2168
2169                 if (parser_read_uint32(&p.match.hash.n_keys,
2170                         tokens[t0 + 11]) != 0) {
2171                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
2172                         return;
2173                 }
2174
2175                 t0 += 12;
2176         } else if (strcmp(tokens[t0], "lpm") == 0) {
2177                 if (n_tokens < t0 + 6) {
2178                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2179                                 "pipeline table lpm");
2180                         return;
2181                 }
2182
2183                 p.match_type = TABLE_LPM;
2184
2185                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
2186                         p.match.lpm.key_size = 4;
2187                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
2188                         p.match.lpm.key_size = 16;
2189                 else {
2190                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2191                                 "ipv4 or ipv6");
2192                         return;
2193                 }
2194
2195                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
2196                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2197                         return;
2198                 }
2199
2200                 if (parser_read_uint32(&p.match.lpm.key_offset,
2201                         tokens[t0 + 3]) != 0) {
2202                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2203                         return;
2204                 }
2205
2206                 if (strcmp(tokens[t0 + 4], "size") != 0) {
2207                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2208                         return;
2209                 }
2210
2211                 if (parser_read_uint32(&p.match.lpm.n_rules,
2212                         tokens[t0 + 5]) != 0) {
2213                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2214                         return;
2215                 }
2216
2217                 t0 += 6;
2218         } else if (strcmp(tokens[t0], "stub") == 0) {
2219                 p.match_type = TABLE_STUB;
2220
2221                 t0 += 1;
2222         } else {
2223                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
2224                 return;
2225         }
2226
2227         p.action_profile_name = NULL;
2228         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
2229                 if (n_tokens < t0 + 2) {
2230                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
2231                         return;
2232                 }
2233
2234                 p.action_profile_name = tokens[t0 + 1];
2235
2236                 t0 += 2;
2237         }
2238
2239         if (n_tokens > t0) {
2240                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2241                 return;
2242         }
2243
2244         status = pipeline_table_create(pipeline_name, &p);
2245         if (status) {
2246                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2247                 return;
2248         }
2249 }
2250
2251 static const char cmd_pipeline_port_in_table_help[] =
2252 "pipeline <pipeline_name> port in <port_id> table <table_id>\n";
2253
2254 static void
2255 cmd_pipeline_port_in_table(char **tokens,
2256         uint32_t n_tokens,
2257         char *out,
2258         size_t out_size)
2259 {
2260         char *pipeline_name;
2261         uint32_t port_id, table_id;
2262         int status;
2263
2264         if (n_tokens != 7) {
2265                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2266                 return;
2267         }
2268
2269         pipeline_name = tokens[1];
2270
2271         if (strcmp(tokens[2], "port") != 0) {
2272                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2273                 return;
2274         }
2275
2276         if (strcmp(tokens[3], "in") != 0) {
2277                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2278                 return;
2279         }
2280
2281         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2282                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2283                 return;
2284         }
2285
2286         if (strcmp(tokens[5], "table") != 0) {
2287                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2288                 return;
2289         }
2290
2291         if (parser_read_uint32(&table_id, tokens[6]) != 0) {
2292                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2293                 return;
2294         }
2295
2296         status = pipeline_port_in_connect_to_table(pipeline_name,
2297                 port_id,
2298                 table_id);
2299         if (status) {
2300                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2301                 return;
2302         }
2303 }
2304
2305
2306 static const char cmd_pipeline_port_in_stats_help[] =
2307 "pipeline <pipeline_name> port in <port_id> stats read [clear]\n";
2308
2309 #define MSG_PIPELINE_PORT_IN_STATS                         \
2310         "Pkts in: %" PRIu64 "\n"                           \
2311         "Pkts dropped by AH: %" PRIu64 "\n"                \
2312         "Pkts dropped by other: %" PRIu64 "\n"
2313
2314 static void
2315 cmd_pipeline_port_in_stats(char **tokens,
2316         uint32_t n_tokens,
2317         char *out,
2318         size_t out_size)
2319 {
2320         struct rte_pipeline_port_in_stats stats;
2321         char *pipeline_name;
2322         uint32_t port_id;
2323         int clear, status;
2324
2325         if ((n_tokens != 7) && (n_tokens != 8)) {
2326                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2327                 return;
2328         }
2329
2330         pipeline_name = tokens[1];
2331
2332         if (strcmp(tokens[2], "port") != 0) {
2333                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2334                 return;
2335         }
2336
2337         if (strcmp(tokens[3], "in") != 0) {
2338                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2339                 return;
2340         }
2341
2342         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2343                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2344                 return;
2345         }
2346
2347         if (strcmp(tokens[5], "stats") != 0) {
2348                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2349                 return;
2350         }
2351
2352         if (strcmp(tokens[6], "read") != 0) {
2353                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2354                 return;
2355         }
2356
2357         clear = 0;
2358         if (n_tokens == 8) {
2359                 if (strcmp(tokens[7], "clear") != 0) {
2360                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2361                         return;
2362                 }
2363
2364                 clear = 1;
2365         }
2366
2367         status = pipeline_port_in_stats_read(pipeline_name,
2368                 port_id,
2369                 &stats,
2370                 clear);
2371         if (status) {
2372                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2373                 return;
2374         }
2375
2376         snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
2377                 stats.stats.n_pkts_in,
2378                 stats.n_pkts_dropped_by_ah,
2379                 stats.stats.n_pkts_drop);
2380 }
2381
2382
2383 static const char cmd_pipeline_port_in_enable_help[] =
2384 "pipeline <pipeline_name> port in <port_id> enable\n";
2385
2386 static void
2387 cmd_pipeline_port_in_enable(char **tokens,
2388         uint32_t n_tokens,
2389         char *out,
2390         size_t out_size)
2391 {
2392         char *pipeline_name;
2393         uint32_t port_id;
2394         int status;
2395
2396         if (n_tokens != 6) {
2397                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2398                 return;
2399         }
2400
2401         pipeline_name = tokens[1];
2402
2403         if (strcmp(tokens[2], "port") != 0) {
2404                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2405                 return;
2406         }
2407
2408         if (strcmp(tokens[3], "in") != 0) {
2409                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2410                 return;
2411         }
2412
2413         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2414                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2415                 return;
2416         }
2417
2418         if (strcmp(tokens[5], "enable") != 0) {
2419                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2420                 return;
2421         }
2422
2423         status = pipeline_port_in_enable(pipeline_name, port_id);
2424         if (status) {
2425                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2426                 return;
2427         }
2428 }
2429
2430
2431 static const char cmd_pipeline_port_in_disable_help[] =
2432 "pipeline <pipeline_name> port in <port_id> disable\n";
2433
2434 static void
2435 cmd_pipeline_port_in_disable(char **tokens,
2436         uint32_t n_tokens,
2437         char *out,
2438         size_t out_size)
2439 {
2440         char *pipeline_name;
2441         uint32_t port_id;
2442         int status;
2443
2444         if (n_tokens != 6) {
2445                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2446                 return;
2447         }
2448
2449         pipeline_name = tokens[1];
2450
2451         if (strcmp(tokens[2], "port") != 0) {
2452                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2453                 return;
2454         }
2455
2456         if (strcmp(tokens[3], "in") != 0) {
2457                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2458                 return;
2459         }
2460
2461         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2462                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2463                 return;
2464         }
2465
2466         if (strcmp(tokens[5], "disable") != 0) {
2467                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2468                 return;
2469         }
2470
2471         status = pipeline_port_in_disable(pipeline_name, port_id);
2472         if (status) {
2473                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2474                 return;
2475         }
2476 }
2477
2478
2479 static const char cmd_pipeline_port_out_stats_help[] =
2480 "pipeline <pipeline_name> port out <port_id> stats read [clear]\n";
2481
2482 #define MSG_PIPELINE_PORT_OUT_STATS                        \
2483         "Pkts in: %" PRIu64 "\n"                           \
2484         "Pkts dropped by AH: %" PRIu64 "\n"                \
2485         "Pkts dropped by other: %" PRIu64 "\n"
2486
2487 static void
2488 cmd_pipeline_port_out_stats(char **tokens,
2489         uint32_t n_tokens,
2490         char *out,
2491         size_t out_size)
2492 {
2493         struct rte_pipeline_port_out_stats stats;
2494         char *pipeline_name;
2495         uint32_t port_id;
2496         int clear, status;
2497
2498         if ((n_tokens != 7) && (n_tokens != 8)) {
2499                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2500                 return;
2501         }
2502
2503         pipeline_name = tokens[1];
2504
2505         if (strcmp(tokens[2], "port") != 0) {
2506                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2507                 return;
2508         }
2509
2510         if (strcmp(tokens[3], "out") != 0) {
2511                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2512                 return;
2513         }
2514
2515         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2516                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2517                 return;
2518         }
2519
2520         if (strcmp(tokens[5], "stats") != 0) {
2521                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2522                 return;
2523         }
2524
2525         if (strcmp(tokens[6], "read") != 0) {
2526                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2527                 return;
2528         }
2529
2530         clear = 0;
2531         if (n_tokens == 8) {
2532                 if (strcmp(tokens[7], "clear") != 0) {
2533                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2534                         return;
2535                 }
2536
2537                 clear = 1;
2538         }
2539
2540         status = pipeline_port_out_stats_read(pipeline_name,
2541                 port_id,
2542                 &stats,
2543                 clear);
2544         if (status) {
2545                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2546                 return;
2547         }
2548
2549         snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
2550                 stats.stats.n_pkts_in,
2551                 stats.n_pkts_dropped_by_ah,
2552                 stats.stats.n_pkts_drop);
2553 }
2554
2555
2556 static const char cmd_pipeline_table_stats_help[] =
2557 "pipeline <pipeline_name> table <table_id> stats read [clear]\n";
2558
2559 #define MSG_PIPELINE_TABLE_STATS                                     \
2560         "Pkts in: %" PRIu64 "\n"                                     \
2561         "Pkts in with lookup miss: %" PRIu64 "\n"                    \
2562         "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
2563         "Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
2564         "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
2565         "Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
2566
2567 static void
2568 cmd_pipeline_table_stats(char **tokens,
2569         uint32_t n_tokens,
2570         char *out,
2571         size_t out_size)
2572 {
2573         struct rte_pipeline_table_stats stats;
2574         char *pipeline_name;
2575         uint32_t table_id;
2576         int clear, status;
2577
2578         if ((n_tokens != 6) && (n_tokens != 7)) {
2579                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2580                 return;
2581         }
2582
2583         pipeline_name = tokens[1];
2584
2585         if (strcmp(tokens[2], "table") != 0) {
2586                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2587                 return;
2588         }
2589
2590         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
2591                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2592                 return;
2593         }
2594
2595         if (strcmp(tokens[4], "stats") != 0) {
2596                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2597                 return;
2598         }
2599
2600         if (strcmp(tokens[5], "read") != 0) {
2601                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2602                 return;
2603         }
2604
2605         clear = 0;
2606         if (n_tokens == 7) {
2607                 if (strcmp(tokens[6], "clear") != 0) {
2608                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2609                         return;
2610                 }
2611
2612                 clear = 1;
2613         }
2614
2615         status = pipeline_table_stats_read(pipeline_name,
2616                 table_id,
2617                 &stats,
2618                 clear);
2619         if (status) {
2620                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2621                 return;
2622         }
2623
2624         snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
2625                 stats.stats.n_pkts_in,
2626                 stats.stats.n_pkts_lookup_miss,
2627                 stats.n_pkts_dropped_by_lkp_hit_ah,
2628                 stats.n_pkts_dropped_lkp_hit,
2629                 stats.n_pkts_dropped_by_lkp_miss_ah,
2630                 stats.n_pkts_dropped_lkp_miss);
2631 }
2632
2633 /**
2634  * <match> ::=
2635  *
2636  * match
2637  *    acl
2638  *       priority <priority>
2639  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
2640  *       <sp0> <sp1> <dp0> <dp1> <proto>
2641  *    | array <pos>
2642  *    | hash
2643  *       raw <key>
2644  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2645  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2646  *       | ipv4_addr <addr>
2647  *       | ipv6_addr <addr>
2648  *       | qinq <svlan> <cvlan>
2649  *    | lpm
2650  *       ipv4 | ipv6 <addr> <depth>
2651  */
2652 struct pkt_key_qinq {
2653         uint16_t ethertype_svlan;
2654         uint16_t svlan;
2655         uint16_t ethertype_cvlan;
2656         uint16_t cvlan;
2657 } __attribute__((__packed__));
2658
2659 struct pkt_key_ipv4_5tuple {
2660         uint8_t time_to_live;
2661         uint8_t proto;
2662         uint16_t hdr_checksum;
2663         uint32_t sa;
2664         uint32_t da;
2665         uint16_t sp;
2666         uint16_t dp;
2667 } __attribute__((__packed__));
2668
2669 struct pkt_key_ipv6_5tuple {
2670         uint16_t payload_length;
2671         uint8_t proto;
2672         uint8_t hop_limit;
2673         uint8_t sa[16];
2674         uint8_t da[16];
2675         uint16_t sp;
2676         uint16_t dp;
2677 } __attribute__((__packed__));
2678
2679 struct pkt_key_ipv4_addr {
2680         uint32_t addr;
2681 } __attribute__((__packed__));
2682
2683 struct pkt_key_ipv6_addr {
2684         uint8_t addr[16];
2685 } __attribute__((__packed__));
2686
2687 static uint32_t
2688 parse_match(char **tokens,
2689         uint32_t n_tokens,
2690         char *out,
2691         size_t out_size,
2692         struct table_rule_match *m)
2693 {
2694         memset(m, 0, sizeof(*m));
2695
2696         if (n_tokens < 2)
2697                 return 0;
2698
2699         if (strcmp(tokens[0], "match") != 0) {
2700                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2701                 return 0;
2702         }
2703
2704         if (strcmp(tokens[1], "acl") == 0) {
2705                 if (n_tokens < 14) {
2706                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2707                         return 0;
2708                 }
2709
2710                 m->match_type = TABLE_ACL;
2711
2712                 if (strcmp(tokens[2], "priority") != 0) {
2713                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
2714                         return 0;
2715                 }
2716
2717                 if (parser_read_uint32(&m->match.acl.priority,
2718                         tokens[3]) != 0) {
2719                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
2720                         return 0;
2721                 }
2722
2723                 if (strcmp(tokens[4], "ipv4") == 0) {
2724                         struct in_addr saddr, daddr;
2725
2726                         m->match.acl.ip_version = 1;
2727
2728                         if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
2729                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2730                                 return 0;
2731                         }
2732                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
2733
2734                         if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
2735                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2736                                 return 0;
2737                         }
2738                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
2739                 } else if (strcmp(tokens[4], "ipv6") == 0) {
2740                         struct in6_addr saddr, daddr;
2741
2742                         m->match.acl.ip_version = 0;
2743
2744                         if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
2745                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2746                                 return 0;
2747                         }
2748                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2749
2750                         if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2751                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2752                                 return 0;
2753                         }
2754                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
2755                 } else {
2756                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2757                                 "ipv4 or ipv6");
2758                         return 0;
2759                 }
2760
2761                 if (parser_read_uint32(&m->match.acl.sa_depth,
2762                         tokens[6]) != 0) {
2763                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
2764                         return 0;
2765                 }
2766
2767                 if (parser_read_uint32(&m->match.acl.da_depth,
2768                         tokens[8]) != 0) {
2769                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
2770                         return 0;
2771                 }
2772
2773                 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
2774                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
2775                         return 0;
2776                 }
2777
2778                 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
2779                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
2780                         return 0;
2781                 }
2782
2783                 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
2784                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
2785                         return 0;
2786                 }
2787
2788                 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
2789                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
2790                         return 0;
2791                 }
2792
2793                 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
2794                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
2795                         return 0;
2796                 }
2797
2798                 m->match.acl.proto_mask = 0xff;
2799
2800                 return 14;
2801         } /* acl */
2802
2803         if (strcmp(tokens[1], "array") == 0) {
2804                 if (n_tokens < 3) {
2805                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2806                         return 0;
2807                 }
2808
2809                 m->match_type = TABLE_ARRAY;
2810
2811                 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
2812                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
2813                         return 0;
2814                 }
2815
2816                 return 3;
2817         } /* array */
2818
2819         if (strcmp(tokens[1], "hash") == 0) {
2820                 if (n_tokens < 3) {
2821                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2822                         return 0;
2823                 }
2824
2825                 m->match_type = TABLE_HASH;
2826
2827                 if (strcmp(tokens[2], "raw") == 0) {
2828                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
2829
2830                         if (n_tokens < 4) {
2831                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2832                                         tokens[0]);
2833                                 return 0;
2834                         }
2835
2836                         if (parse_hex_string(tokens[3],
2837                                 m->match.hash.key, &key_size) != 0) {
2838                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
2839                                 return 0;
2840                         }
2841
2842                         return 4;
2843                 } /* hash raw */
2844
2845                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
2846                         struct pkt_key_ipv4_5tuple *ipv4 =
2847                                 (struct pkt_key_ipv4_5tuple *) m->match.hash.key;
2848                         struct in_addr saddr, daddr;
2849                         uint16_t sp, dp;
2850                         uint8_t proto;
2851
2852                         if (n_tokens < 8) {
2853                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2854                                         tokens[0]);
2855                                 return 0;
2856                         }
2857
2858                         if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
2859                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2860                                 return 0;
2861                         }
2862
2863                         if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
2864                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2865                                 return 0;
2866                         }
2867
2868                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2869                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2870                                 return 0;
2871                         }
2872
2873                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2874                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2875                                 return 0;
2876                         }
2877
2878                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2879                                 snprintf(out, out_size, MSG_ARG_INVALID,
2880                                         "proto");
2881                                 return 0;
2882                         }
2883
2884                         ipv4->sa = saddr.s_addr;
2885                         ipv4->da = daddr.s_addr;
2886                         ipv4->sp = rte_cpu_to_be_16(sp);
2887                         ipv4->dp = rte_cpu_to_be_16(dp);
2888                         ipv4->proto = proto;
2889
2890                         return 8;
2891                 } /* hash ipv4_5tuple */
2892
2893                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
2894                         struct pkt_key_ipv6_5tuple *ipv6 =
2895                                 (struct pkt_key_ipv6_5tuple *) m->match.hash.key;
2896                         struct in6_addr saddr, daddr;
2897                         uint16_t sp, dp;
2898                         uint8_t proto;
2899
2900                         if (n_tokens < 8) {
2901                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2902                                         tokens[0]);
2903                                 return 0;
2904                         }
2905
2906                         if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
2907                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2908                                 return 0;
2909                         }
2910
2911                         if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
2912                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2913                                 return 0;
2914                         }
2915
2916                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2917                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2918                                 return 0;
2919                         }
2920
2921                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2922                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2923                                 return 0;
2924                         }
2925
2926                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2927                                 snprintf(out, out_size, MSG_ARG_INVALID,
2928                                         "proto");
2929                                 return 0;
2930                         }
2931
2932                         memcpy(ipv6->sa, saddr.s6_addr, 16);
2933                         memcpy(ipv6->da, daddr.s6_addr, 16);
2934                         ipv6->sp = rte_cpu_to_be_16(sp);
2935                         ipv6->dp = rte_cpu_to_be_16(dp);
2936                         ipv6->proto = proto;
2937
2938                         return 8;
2939                 } /* hash ipv6_5tuple */
2940
2941                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
2942                         struct pkt_key_ipv4_addr *ipv4_addr =
2943                                 (struct pkt_key_ipv4_addr *) m->match.hash.key;
2944                         struct in_addr addr;
2945
2946                         if (n_tokens < 4) {
2947                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2948                                         tokens[0]);
2949                                 return 0;
2950                         }
2951
2952                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2953                                 snprintf(out, out_size, MSG_ARG_INVALID,
2954                                         "addr");
2955                                 return 0;
2956                         }
2957
2958                         ipv4_addr->addr = addr.s_addr;
2959
2960                         return 4;
2961                 } /* hash ipv4_addr */
2962
2963                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
2964                         struct pkt_key_ipv6_addr *ipv6_addr =
2965                                 (struct pkt_key_ipv6_addr *) m->match.hash.key;
2966                         struct in6_addr addr;
2967
2968                         if (n_tokens < 4) {
2969                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2970                                         tokens[0]);
2971                                 return 0;
2972                         }
2973
2974                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2975                                 snprintf(out, out_size, MSG_ARG_INVALID,
2976                                         "addr");
2977                                 return 0;
2978                         }
2979
2980                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
2981
2982                         return 4;
2983                 } /* hash ipv6_5tuple */
2984
2985                 if (strcmp(tokens[2], "qinq") == 0) {
2986                         struct pkt_key_qinq *qinq =
2987                                 (struct pkt_key_qinq *) m->match.hash.key;
2988                         uint16_t svlan, cvlan;
2989
2990                         if (n_tokens < 5) {
2991                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2992                                         tokens[0]);
2993                                 return 0;
2994                         }
2995
2996                         if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
2997                                 (svlan > 0xFFF)) {
2998                                 snprintf(out, out_size, MSG_ARG_INVALID,
2999                                         "svlan");
3000                                 return 0;
3001                         }
3002
3003                         if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
3004                                 (cvlan > 0xFFF)) {
3005                                 snprintf(out, out_size, MSG_ARG_INVALID,
3006                                         "cvlan");
3007                                 return 0;
3008                         }
3009
3010                         qinq->svlan = rte_cpu_to_be_16(svlan);
3011                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
3012
3013                         return 5;
3014                 } /* hash qinq */
3015
3016                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3017                 return 0;
3018         } /* hash */
3019
3020         if (strcmp(tokens[1], "lpm") == 0) {
3021                 if (n_tokens < 5) {
3022                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3023                         return 0;
3024                 }
3025
3026                 m->match_type = TABLE_LPM;
3027
3028                 if (strcmp(tokens[2], "ipv4") == 0) {
3029                         struct in_addr addr;
3030
3031                         m->match.lpm.ip_version = 1;
3032
3033                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
3034                                 snprintf(out, out_size, MSG_ARG_INVALID,
3035                                         "addr");
3036                                 return 0;
3037                         }
3038
3039                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3040                 } else if (strcmp(tokens[2], "ipv6") == 0) {
3041                         struct in6_addr addr;
3042
3043                         m->match.lpm.ip_version = 0;
3044
3045                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
3046                                 snprintf(out, out_size, MSG_ARG_INVALID,
3047                                         "addr");
3048                                 return 0;
3049                         }
3050
3051                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
3052                 } else {
3053                         snprintf(out, out_size, MSG_ARG_MISMATCH,
3054                                 "ipv4 or ipv6");
3055                         return 0;
3056                 }
3057
3058                 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
3059                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
3060                         return 0;
3061                 }
3062
3063                 return 5;
3064         } /* lpm */
3065
3066         snprintf(out, out_size, MSG_ARG_MISMATCH,
3067                 "acl or array or hash or lpm");
3068         return 0;
3069 }
3070
3071 /**
3072  * table_action ::=
3073  *
3074  * action
3075  *    fwd
3076  *       drop
3077  *       | port <port_id>
3078  *       | meta
3079  *       | table <table_id>
3080  *    [balance <out0> ... <out7>]
3081  *    [meter
3082  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3083  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3084  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3085  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
3086  *    [tm subport <subport_id> pipe <pipe_id>]
3087  *    [encap
3088  *       ether <da> <sa>
3089  *       | vlan <da> <sa> <pcp> <dei> <vid>
3090  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
3091  *       | qinq_pppoe <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid> <session_id>
3092  *       | mpls unicast | multicast
3093  *          <da> <sa>
3094  *          label0 <label> <tc> <ttl>
3095  *          [label1 <label> <tc> <ttl>
3096  *          [label2 <label> <tc> <ttl>
3097  *          [label3 <label> <tc> <ttl>]]]
3098  *       | pppoe <da> <sa> <session_id>
3099  *       | vxlan ether <da> <sa>
3100  *          [vlan <pcp> <dei> <vid>]
3101  *          ipv4 <sa> <da> <dscp> <ttl>
3102  *          | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit>
3103  *          udp <sp> <dp>
3104  *          vxlan <vni>]
3105  *    [nat ipv4 | ipv6 <addr> <port>]
3106  *    [ttl dec | keep]
3107  *    [stats]
3108  *    [time]
3109  *    [sym_crypto
3110  *       encrypt | decrypt
3111  *       type
3112  *       | cipher
3113  *          cipher_algo <algo> cipher_key <key> cipher_iv <iv>
3114  *       | cipher_auth
3115  *          cipher_algo <algo> cipher_key <key> cipher_iv <iv>
3116  *          auth_algo <algo> auth_key <key> digest_size <size>
3117  *       | aead
3118  *          aead_algo <algo> aead_key <key> aead_iv <iv> aead_aad <aad>
3119  *          digest_size <size>
3120  *       data_offset <data_offset>]
3121  *    [tag <tag>]
3122  *    [decap <n>]
3123  *
3124  * where:
3125  *    <pa> ::= g | y | r | drop
3126  */
3127 static uint32_t
3128 parse_table_action_fwd(char **tokens,
3129         uint32_t n_tokens,
3130         struct table_rule_action *a)
3131 {
3132         if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
3133                 return 0;
3134
3135         tokens++;
3136         n_tokens--;
3137
3138         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
3139                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
3140                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3141                 return 1 + 1;
3142         }
3143
3144         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
3145                 uint32_t id;
3146
3147                 if ((n_tokens < 2) ||
3148                         parser_read_uint32(&id, tokens[1]))
3149                         return 0;
3150
3151                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
3152                 a->fwd.id = id;
3153                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3154                 return 1 + 2;
3155         }
3156
3157         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
3158                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3159                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3160                 return 1 + 1;
3161         }
3162
3163         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
3164                 uint32_t id;
3165
3166                 if ((n_tokens < 2) ||
3167                         parser_read_uint32(&id, tokens[1]))
3168                         return 0;
3169
3170                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
3171                 a->fwd.id = id;
3172                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3173                 return 1 + 2;
3174         }
3175
3176         return 0;
3177 }
3178
3179 static uint32_t
3180 parse_table_action_balance(char **tokens,
3181         uint32_t n_tokens,
3182         struct table_rule_action *a)
3183 {
3184         uint32_t i;
3185
3186         if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0))
3187                 return 0;
3188
3189         tokens++;
3190         n_tokens--;
3191
3192         if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE)
3193                 return 0;
3194
3195         for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++)
3196                 if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
3197                         return 0;
3198
3199         a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
3200         return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE;
3201
3202 }
3203
3204 static int
3205 parse_policer_action(char *token, enum rte_table_action_policer *a)
3206 {
3207         if (strcmp(token, "g") == 0) {
3208                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
3209                 return 0;
3210         }
3211
3212         if (strcmp(token, "y") == 0) {
3213                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
3214                 return 0;
3215         }
3216
3217         if (strcmp(token, "r") == 0) {
3218                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
3219                 return 0;
3220         }
3221
3222         if (strcmp(token, "drop") == 0) {
3223                 *a = RTE_TABLE_ACTION_POLICER_DROP;
3224                 return 0;
3225         }
3226
3227         return -1;
3228 }
3229
3230 static uint32_t
3231 parse_table_action_meter_tc(char **tokens,
3232         uint32_t n_tokens,
3233         struct rte_table_action_mtr_tc_params *mtr)
3234 {
3235         if ((n_tokens < 9) ||
3236                 strcmp(tokens[0], "meter") ||
3237                 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
3238                 strcmp(tokens[2], "policer") ||
3239                 strcmp(tokens[3], "g") ||
3240                 parse_policer_action(tokens[4], &mtr->policer[RTE_COLOR_GREEN]) ||
3241                 strcmp(tokens[5], "y") ||
3242                 parse_policer_action(tokens[6], &mtr->policer[RTE_COLOR_YELLOW]) ||
3243                 strcmp(tokens[7], "r") ||
3244                 parse_policer_action(tokens[8], &mtr->policer[RTE_COLOR_RED]))
3245                 return 0;
3246
3247         return 9;
3248 }
3249
3250 static uint32_t
3251 parse_table_action_meter(char **tokens,
3252         uint32_t n_tokens,
3253         struct table_rule_action *a)
3254 {
3255         if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
3256                 return 0;
3257
3258         tokens++;
3259         n_tokens--;
3260
3261         if ((n_tokens < 10) ||
3262                 strcmp(tokens[0], "tc0") ||
3263                 (parse_table_action_meter_tc(tokens + 1,
3264                         n_tokens - 1,
3265                         &a->mtr.mtr[0]) == 0))
3266                 return 0;
3267
3268         tokens += 10;
3269         n_tokens -= 10;
3270
3271         if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
3272                 a->mtr.tc_mask = 1;
3273                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3274                 return 1 + 10;
3275         }
3276
3277         if ((n_tokens < 30) ||
3278                 (parse_table_action_meter_tc(tokens + 1,
3279                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
3280                 strcmp(tokens[10], "tc2") ||
3281                 (parse_table_action_meter_tc(tokens + 11,
3282                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
3283                 strcmp(tokens[20], "tc3") ||
3284                 (parse_table_action_meter_tc(tokens + 21,
3285                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
3286                 return 0;
3287
3288         a->mtr.tc_mask = 0xF;
3289         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3290         return 1 + 10 + 3 * 10;
3291 }
3292
3293 static uint32_t
3294 parse_table_action_tm(char **tokens,
3295         uint32_t n_tokens,
3296         struct table_rule_action *a)
3297 {
3298         uint32_t subport_id, pipe_id;
3299
3300         if ((n_tokens < 5) ||
3301                 strcmp(tokens[0], "tm") ||
3302                 strcmp(tokens[1], "subport") ||
3303                 parser_read_uint32(&subport_id, tokens[2]) ||
3304                 strcmp(tokens[3], "pipe") ||
3305                 parser_read_uint32(&pipe_id, tokens[4]))
3306                 return 0;
3307
3308         a->tm.subport_id = subport_id;
3309         a->tm.pipe_id = pipe_id;
3310         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
3311         return 5;
3312 }
3313
3314 static uint32_t
3315 parse_table_action_encap(char **tokens,
3316         uint32_t n_tokens,
3317         struct table_rule_action *a)
3318 {
3319         if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
3320                 return 0;
3321
3322         tokens++;
3323         n_tokens--;
3324
3325         /* ether */
3326         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
3327                 if ((n_tokens < 3) ||
3328                         parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
3329                         parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
3330                         return 0;
3331
3332                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
3333                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3334                 return 1 + 3;
3335         }
3336
3337         /* vlan */
3338         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
3339                 uint32_t pcp, dei, vid;
3340
3341                 if ((n_tokens < 6) ||
3342                         parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
3343                         parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
3344                         parser_read_uint32(&pcp, tokens[3]) ||
3345                         (pcp > 0x7) ||
3346                         parser_read_uint32(&dei, tokens[4]) ||
3347                         (dei > 0x1) ||
3348                         parser_read_uint32(&vid, tokens[5]) ||
3349                         (vid > 0xFFF))
3350                         return 0;
3351
3352                 a->encap.vlan.vlan.pcp = pcp & 0x7;
3353                 a->encap.vlan.vlan.dei = dei & 0x1;
3354                 a->encap.vlan.vlan.vid = vid & 0xFFF;
3355                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
3356                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3357                 return 1 + 6;
3358         }
3359
3360         /* qinq */
3361         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
3362                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
3363                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3364
3365                 if ((n_tokens < 9) ||
3366                         parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
3367                         parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
3368                         parser_read_uint32(&svlan_pcp, tokens[3]) ||
3369                         (svlan_pcp > 0x7) ||
3370                         parser_read_uint32(&svlan_dei, tokens[4]) ||
3371                         (svlan_dei > 0x1) ||
3372                         parser_read_uint32(&svlan_vid, tokens[5]) ||
3373                         (svlan_vid > 0xFFF) ||
3374                         parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3375                         (cvlan_pcp > 0x7) ||
3376                         parser_read_uint32(&cvlan_dei, tokens[7]) ||
3377                         (cvlan_dei > 0x1) ||
3378                         parser_read_uint32(&cvlan_vid, tokens[8]) ||
3379                         (cvlan_vid > 0xFFF))
3380                         return 0;
3381
3382                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
3383                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
3384                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
3385                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
3386                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
3387                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
3388                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
3389                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3390                 return 1 + 9;
3391         }
3392
3393         /* qinq_pppoe */
3394         if (n_tokens && (strcmp(tokens[0], "qinq_pppoe") == 0)) {
3395                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
3396                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3397
3398                 if ((n_tokens < 10) ||
3399                         parse_mac_addr(tokens[1],
3400                                 &a->encap.qinq_pppoe.ether.da) ||
3401                         parse_mac_addr(tokens[2],
3402                                 &a->encap.qinq_pppoe.ether.sa) ||
3403                         parser_read_uint32(&svlan_pcp, tokens[3]) ||
3404                         (svlan_pcp > 0x7) ||
3405                         parser_read_uint32(&svlan_dei, tokens[4]) ||
3406                         (svlan_dei > 0x1) ||
3407                         parser_read_uint32(&svlan_vid, tokens[5]) ||
3408                         (svlan_vid > 0xFFF) ||
3409                         parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3410                         (cvlan_pcp > 0x7) ||
3411                         parser_read_uint32(&cvlan_dei, tokens[7]) ||
3412                         (cvlan_dei > 0x1) ||
3413                         parser_read_uint32(&cvlan_vid, tokens[8]) ||
3414                         (cvlan_vid > 0xFFF) ||
3415                         parser_read_uint16(&a->encap.qinq_pppoe.pppoe.session_id,
3416                                 tokens[9]))
3417                         return 0;
3418
3419                 a->encap.qinq_pppoe.svlan.pcp = svlan_pcp & 0x7;
3420                 a->encap.qinq_pppoe.svlan.dei = svlan_dei & 0x1;
3421                 a->encap.qinq_pppoe.svlan.vid = svlan_vid & 0xFFF;
3422                 a->encap.qinq_pppoe.cvlan.pcp = cvlan_pcp & 0x7;
3423                 a->encap.qinq_pppoe.cvlan.dei = cvlan_dei & 0x1;
3424                 a->encap.qinq_pppoe.cvlan.vid = cvlan_vid & 0xFFF;
3425                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ_PPPOE;
3426                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3427                 return 1 + 10;
3428
3429         }
3430
3431         /* mpls */
3432         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
3433                 uint32_t label, tc, ttl;
3434
3435                 if (n_tokens < 8)
3436                         return 0;
3437
3438                 if (strcmp(tokens[1], "unicast") == 0)
3439                         a->encap.mpls.unicast = 1;
3440                 else if (strcmp(tokens[1], "multicast") == 0)
3441                         a->encap.mpls.unicast = 0;
3442                 else
3443                         return 0;
3444
3445                 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
3446                         parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
3447                         strcmp(tokens[4], "label0") ||
3448                         parser_read_uint32(&label, tokens[5]) ||
3449                         (label > 0xFFFFF) ||
3450                         parser_read_uint32(&tc, tokens[6]) ||
3451                         (tc > 0x7) ||
3452                         parser_read_uint32(&ttl, tokens[7]) ||
3453                         (ttl > 0x3F))
3454                         return 0;
3455
3456                 a->encap.mpls.mpls[0].label = label;
3457                 a->encap.mpls.mpls[0].tc = tc;
3458                 a->encap.mpls.mpls[0].ttl = ttl;
3459
3460                 tokens += 8;
3461                 n_tokens -= 8;
3462
3463                 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
3464                         a->encap.mpls.mpls_count = 1;
3465                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3466                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3467                         return 1 + 8;
3468                 }
3469
3470                 if ((n_tokens < 4) ||
3471                         parser_read_uint32(&label, tokens[1]) ||
3472                         (label > 0xFFFFF) ||
3473                         parser_read_uint32(&tc, tokens[2]) ||
3474                         (tc > 0x7) ||
3475                         parser_read_uint32(&ttl, tokens[3]) ||
3476                         (ttl > 0x3F))
3477                         return 0;
3478
3479                 a->encap.mpls.mpls[1].label = label;
3480                 a->encap.mpls.mpls[1].tc = tc;
3481                 a->encap.mpls.mpls[1].ttl = ttl;
3482
3483                 tokens += 4;
3484                 n_tokens -= 4;
3485
3486                 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
3487                         a->encap.mpls.mpls_count = 2;
3488                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3489                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3490                         return 1 + 8 + 4;
3491                 }
3492
3493                 if ((n_tokens < 4) ||
3494                         parser_read_uint32(&label, tokens[1]) ||
3495                         (label > 0xFFFFF) ||
3496                         parser_read_uint32(&tc, tokens[2]) ||
3497                         (tc > 0x7) ||
3498                         parser_read_uint32(&ttl, tokens[3]) ||
3499                         (ttl > 0x3F))
3500                         return 0;
3501
3502                 a->encap.mpls.mpls[2].label = label;
3503                 a->encap.mpls.mpls[2].tc = tc;
3504                 a->encap.mpls.mpls[2].ttl = ttl;
3505
3506                 tokens += 4;
3507                 n_tokens -= 4;
3508
3509                 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
3510                         a->encap.mpls.mpls_count = 3;
3511                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3512                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3513                         return 1 + 8 + 4 + 4;
3514                 }
3515
3516                 if ((n_tokens < 4) ||
3517                         parser_read_uint32(&label, tokens[1]) ||
3518                         (label > 0xFFFFF) ||
3519                         parser_read_uint32(&tc, tokens[2]) ||
3520                         (tc > 0x7) ||
3521                         parser_read_uint32(&ttl, tokens[3]) ||
3522                         (ttl > 0x3F))
3523                         return 0;
3524
3525                 a->encap.mpls.mpls[3].label = label;
3526                 a->encap.mpls.mpls[3].tc = tc;
3527                 a->encap.mpls.mpls[3].ttl = ttl;
3528
3529                 a->encap.mpls.mpls_count = 4;
3530                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3531                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3532                 return 1 + 8 + 4 + 4 + 4;
3533         }
3534
3535         /* pppoe */
3536         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3537                 if ((n_tokens < 4) ||
3538                         parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3539                         parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3540                         parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3541                                 tokens[3]))
3542                         return 0;
3543
3544                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3545                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3546                 return 1 + 4;
3547         }
3548
3549         /* vxlan */
3550         if (n_tokens && (strcmp(tokens[0], "vxlan") == 0)) {
3551                 uint32_t n = 0;
3552
3553                 n_tokens--;
3554                 tokens++;
3555                 n++;
3556
3557                 /* ether <da> <sa> */
3558                 if ((n_tokens < 3) ||
3559                         strcmp(tokens[0], "ether") ||
3560                         parse_mac_addr(tokens[1], &a->encap.vxlan.ether.da) ||
3561                         parse_mac_addr(tokens[2], &a->encap.vxlan.ether.sa))
3562                         return 0;
3563
3564                 n_tokens -= 3;
3565                 tokens += 3;
3566                 n += 3;
3567
3568                 /* [vlan <pcp> <dei> <vid>] */
3569                 if (strcmp(tokens[0], "vlan") == 0) {
3570                         uint32_t pcp, dei, vid;
3571
3572                         if ((n_tokens < 4) ||
3573                                 parser_read_uint32(&pcp, tokens[1]) ||
3574                                 (pcp > 7) ||
3575                                 parser_read_uint32(&dei, tokens[2]) ||
3576                                 (dei > 1) ||
3577                                 parser_read_uint32(&vid, tokens[3]) ||
3578                                 (vid > 0xFFF))
3579                                 return 0;
3580
3581                         a->encap.vxlan.vlan.pcp = pcp;
3582                         a->encap.vxlan.vlan.dei = dei;
3583                         a->encap.vxlan.vlan.vid = vid;
3584
3585                         n_tokens -= 4;
3586                         tokens += 4;
3587                         n += 4;
3588                 }
3589
3590                 /* ipv4 <sa> <da> <dscp> <ttl>
3591                    | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> */
3592                 if (strcmp(tokens[0], "ipv4") == 0) {
3593                         struct in_addr sa, da;
3594                         uint8_t dscp, ttl;
3595
3596                         if ((n_tokens < 5) ||
3597                                 parse_ipv4_addr(tokens[1], &sa) ||
3598                                 parse_ipv4_addr(tokens[2], &da) ||
3599                                 parser_read_uint8(&dscp, tokens[3]) ||
3600                                 (dscp > 64) ||
3601                                 parser_read_uint8(&ttl, tokens[4]))
3602                                 return 0;
3603
3604                         a->encap.vxlan.ipv4.sa = rte_be_to_cpu_32(sa.s_addr);
3605                         a->encap.vxlan.ipv4.da = rte_be_to_cpu_32(da.s_addr);
3606                         a->encap.vxlan.ipv4.dscp = dscp;
3607                         a->encap.vxlan.ipv4.ttl = ttl;
3608
3609                         n_tokens -= 5;
3610                         tokens += 5;
3611                         n += 5;
3612                 } else if (strcmp(tokens[0], "ipv6") == 0) {
3613                         struct in6_addr sa, da;
3614                         uint32_t flow_label;
3615                         uint8_t dscp, hop_limit;
3616
3617                         if ((n_tokens < 6) ||
3618                                 parse_ipv6_addr(tokens[1], &sa) ||
3619                                 parse_ipv6_addr(tokens[2], &da) ||
3620                                 parser_read_uint32(&flow_label, tokens[3]) ||
3621                                 parser_read_uint8(&dscp, tokens[4]) ||
3622                                 (dscp > 64) ||
3623                                 parser_read_uint8(&hop_limit, tokens[5]))
3624                                 return 0;
3625
3626                         memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16);
3627                         memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16);
3628                         a->encap.vxlan.ipv6.flow_label = flow_label;
3629                         a->encap.vxlan.ipv6.dscp = dscp;
3630                         a->encap.vxlan.ipv6.hop_limit = hop_limit;
3631
3632                         n_tokens -= 6;
3633                         tokens += 6;
3634                         n += 6;
3635                 } else
3636                         return 0;
3637
3638                 /* udp <sp> <dp> */
3639                 if ((n_tokens < 3) ||
3640                         strcmp(tokens[0], "udp") ||
3641                         parser_read_uint16(&a->encap.vxlan.udp.sp, tokens[1]) ||
3642                         parser_read_uint16(&a->encap.vxlan.udp.dp, tokens[2]))
3643                         return 0;
3644
3645                 n_tokens -= 3;
3646                 tokens += 3;
3647                 n += 3;
3648
3649                 /* vxlan <vni> */
3650                 if ((n_tokens < 2) ||
3651                         strcmp(tokens[0], "vxlan") ||
3652                         parser_read_uint32(&a->encap.vxlan.vxlan.vni, tokens[1]) ||
3653                         (a->encap.vxlan.vxlan.vni > 0xFFFFFF))
3654                         return 0;
3655
3656                 n_tokens -= 2;
3657                 tokens += 2;
3658                 n += 2;
3659
3660                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN;
3661                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3662                 return 1 + n;
3663         }
3664
3665         return 0;
3666 }
3667
3668 static uint32_t
3669 parse_table_action_nat(char **tokens,
3670         uint32_t n_tokens,
3671         struct table_rule_action *a)
3672 {
3673         if ((n_tokens < 4) ||
3674                 strcmp(tokens[0], "nat"))
3675                 return 0;
3676
3677         if (strcmp(tokens[1], "ipv4") == 0) {
3678                 struct in_addr addr;
3679                 uint16_t port;
3680
3681                 if (parse_ipv4_addr(tokens[2], &addr) ||
3682                         parser_read_uint16(&port, tokens[3]))
3683                         return 0;
3684
3685                 a->nat.ip_version = 1;
3686                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3687                 a->nat.port = port;
3688                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3689                 return 4;
3690         }
3691
3692         if (strcmp(tokens[1], "ipv6") == 0) {
3693                 struct in6_addr addr;
3694                 uint16_t port;
3695
3696                 if (parse_ipv6_addr(tokens[2], &addr) ||
3697                         parser_read_uint16(&port, tokens[3]))
3698                         return 0;
3699
3700                 a->nat.ip_version = 0;
3701                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3702                 a->nat.port = port;
3703                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3704                 return 4;
3705         }
3706
3707         return 0;
3708 }
3709
3710 static uint32_t
3711 parse_table_action_ttl(char **tokens,
3712         uint32_t n_tokens,
3713         struct table_rule_action *a)
3714 {
3715         if ((n_tokens < 2) ||
3716                 strcmp(tokens[0], "ttl"))
3717                 return 0;
3718
3719         if (strcmp(tokens[1], "dec") == 0)
3720                 a->ttl.decrement = 1;
3721         else if (strcmp(tokens[1], "keep") == 0)
3722                 a->ttl.decrement = 0;
3723         else
3724                 return 0;
3725
3726         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
3727         return 2;
3728 }
3729
3730 static uint32_t
3731 parse_table_action_stats(char **tokens,
3732         uint32_t n_tokens,
3733         struct table_rule_action *a)
3734 {
3735         if ((n_tokens < 1) ||
3736                 strcmp(tokens[0], "stats"))
3737                 return 0;
3738
3739         a->stats.n_packets = 0;
3740         a->stats.n_bytes = 0;
3741         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
3742         return 1;
3743 }
3744
3745 static uint32_t
3746 parse_table_action_time(char **tokens,
3747         uint32_t n_tokens,
3748         struct table_rule_action *a)
3749 {
3750         if ((n_tokens < 1) ||
3751                 strcmp(tokens[0], "time"))
3752                 return 0;
3753
3754         a->time.time = rte_rdtsc();
3755         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
3756         return 1;
3757 }
3758
3759 static void
3760 parse_free_sym_crypto_param_data(struct rte_table_action_sym_crypto_params *p)
3761 {
3762         struct rte_crypto_sym_xform *xform[2] = {NULL};
3763         uint32_t i;
3764
3765         xform[0] = p->xform;
3766         if (xform[0])
3767                 xform[1] = xform[0]->next;
3768
3769         for (i = 0; i < 2; i++) {
3770                 if (xform[i] == NULL)
3771                         continue;
3772
3773                 switch (xform[i]->type) {
3774                 case RTE_CRYPTO_SYM_XFORM_CIPHER:
3775                         if (p->cipher_auth.cipher_iv.val)
3776                                 free(p->cipher_auth.cipher_iv.val);
3777                         if (p->cipher_auth.cipher_iv_update.val)
3778                                 free(p->cipher_auth.cipher_iv_update.val);
3779                         break;
3780                 case RTE_CRYPTO_SYM_XFORM_AUTH:
3781                         if (p->cipher_auth.auth_iv.val)
3782                                 free(p->cipher_auth.cipher_iv.val);
3783                         if (p->cipher_auth.auth_iv_update.val)
3784                                 free(p->cipher_auth.cipher_iv_update.val);
3785                         break;
3786                 case RTE_CRYPTO_SYM_XFORM_AEAD:
3787                         if (p->aead.iv.val)
3788                                 free(p->aead.iv.val);
3789                         if (p->aead.aad.val)
3790                                 free(p->aead.aad.val);
3791                         break;
3792                 default:
3793                         continue;
3794                 }
3795         }
3796
3797 }
3798
3799 static struct rte_crypto_sym_xform *
3800 parse_table_action_cipher(struct rte_table_action_sym_crypto_params *p,
3801                 uint8_t *key, uint32_t max_key_len, char **tokens,
3802                 uint32_t n_tokens, uint32_t encrypt, uint32_t *used_n_tokens)
3803 {
3804         struct rte_crypto_sym_xform *xform_cipher;
3805         int status;
3806         size_t len;
3807
3808         if (n_tokens < 7 || strcmp(tokens[1], "cipher_algo") ||
3809                         strcmp(tokens[3], "cipher_key") ||
3810                         strcmp(tokens[5], "cipher_iv"))
3811                 return NULL;
3812
3813         xform_cipher = calloc(1, sizeof(*xform_cipher));
3814         if (xform_cipher == NULL)
3815                 return NULL;
3816
3817         xform_cipher->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
3818         xform_cipher->cipher.op = encrypt ? RTE_CRYPTO_CIPHER_OP_ENCRYPT :
3819                         RTE_CRYPTO_CIPHER_OP_DECRYPT;
3820
3821         /* cipher_algo */
3822         status = rte_cryptodev_get_cipher_algo_enum(
3823                         &xform_cipher->cipher.algo, tokens[2]);
3824         if (status < 0)
3825                 goto error_exit;
3826
3827         /* cipher_key */
3828         len = strlen(tokens[4]);
3829         if (len / 2 > max_key_len) {
3830                 status = -ENOMEM;
3831                 goto error_exit;
3832         }
3833
3834         status = parse_hex_string(tokens[4], key, (uint32_t *)&len);
3835         if (status < 0)
3836                 goto error_exit;
3837
3838         xform_cipher->cipher.key.data = key;
3839         xform_cipher->cipher.key.length = (uint16_t)len;
3840
3841         /* cipher_iv */
3842         len = strlen(tokens[6]);
3843
3844         p->cipher_auth.cipher_iv.val = calloc(1, len / 2 + 1);
3845         if (p->cipher_auth.cipher_iv.val == NULL)
3846                 goto error_exit;
3847
3848         status = parse_hex_string(tokens[6],
3849                         p->cipher_auth.cipher_iv.val,
3850                         (uint32_t *)&len);
3851         if (status < 0)
3852                 goto error_exit;
3853
3854         xform_cipher->cipher.iv.length = (uint16_t)len;
3855         xform_cipher->cipher.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
3856         p->cipher_auth.cipher_iv.length = (uint32_t)len;
3857         *used_n_tokens = 7;
3858
3859         return xform_cipher;
3860
3861 error_exit:
3862         if (p->cipher_auth.cipher_iv.val) {
3863                 free(p->cipher_auth.cipher_iv.val);
3864                 p->cipher_auth.cipher_iv.val = NULL;
3865         }
3866
3867         free(xform_cipher);
3868
3869         return NULL;
3870 }
3871
3872 static struct rte_crypto_sym_xform *
3873 parse_table_action_cipher_auth(struct rte_table_action_sym_crypto_params *p,
3874                 uint8_t *key, uint32_t max_key_len, char **tokens,
3875                 uint32_t n_tokens, uint32_t encrypt, uint32_t *used_n_tokens)
3876 {
3877         struct rte_crypto_sym_xform *xform_cipher;
3878         struct rte_crypto_sym_xform *xform_auth;
3879         int status;
3880         size_t len;
3881
3882         if (n_tokens < 13 ||
3883                         strcmp(tokens[7], "auth_algo") ||
3884                         strcmp(tokens[9], "auth_key") ||
3885                         strcmp(tokens[11], "digest_size"))
3886                 return NULL;
3887
3888         xform_auth = calloc(1, sizeof(*xform_auth));
3889         if (xform_auth == NULL)
3890                 return NULL;
3891
3892         xform_auth->type = RTE_CRYPTO_SYM_XFORM_AUTH;
3893         xform_auth->auth.op = encrypt ? RTE_CRYPTO_AUTH_OP_GENERATE :
3894                         RTE_CRYPTO_AUTH_OP_VERIFY;
3895
3896         /* auth_algo */
3897         status = rte_cryptodev_get_auth_algo_enum(&xform_auth->auth.algo,
3898                         tokens[8]);
3899         if (status < 0)
3900                 goto error_exit;
3901
3902         /* auth_key */
3903         len = strlen(tokens[10]);
3904         if (len / 2 > max_key_len) {
3905                 status = -ENOMEM;
3906                 goto error_exit;
3907         }
3908
3909         status = parse_hex_string(tokens[10], key, (uint32_t *)&len);
3910         if (status < 0)
3911                 goto error_exit;
3912
3913         xform_auth->auth.key.data = key;
3914         xform_auth->auth.key.length = (uint16_t)len;
3915
3916         key += xform_auth->auth.key.length;
3917         max_key_len -= xform_auth->auth.key.length;
3918
3919         if (strcmp(tokens[11], "digest_size"))
3920                 goto error_exit;
3921
3922         status = parser_read_uint16(&xform_auth->auth.digest_length,
3923                         tokens[12]);
3924         if (status < 0)
3925                 goto error_exit;
3926
3927         xform_cipher = parse_table_action_cipher(p, key, max_key_len, tokens,
3928                         7, encrypt, used_n_tokens);
3929         if (xform_cipher == NULL)
3930                 goto error_exit;
3931
3932         *used_n_tokens += 6;
3933
3934         if (encrypt) {
3935                 xform_cipher->next = xform_auth;
3936                 return xform_cipher;
3937         } else {
3938                 xform_auth->next = xform_cipher;
3939                 return xform_auth;
3940         }
3941
3942 error_exit:
3943         if (p->cipher_auth.auth_iv.val) {
3944                 free(p->cipher_auth.auth_iv.val);
3945                 p->cipher_auth.auth_iv.val = 0;
3946         }
3947
3948         free(xform_auth);
3949
3950         return NULL;
3951 }
3952
3953 static struct rte_crypto_sym_xform *
3954 parse_table_action_aead(struct rte_table_action_sym_crypto_params *p,
3955                 uint8_t *key, uint32_t max_key_len, char **tokens,
3956                 uint32_t n_tokens, uint32_t encrypt, uint32_t *used_n_tokens)
3957 {
3958         struct rte_crypto_sym_xform *xform_aead;
3959         int status;
3960         size_t len;
3961
3962         if (n_tokens < 11 || strcmp(tokens[1], "aead_algo") ||
3963                         strcmp(tokens[3], "aead_key") ||
3964                         strcmp(tokens[5], "aead_iv") ||
3965                         strcmp(tokens[7], "aead_aad") ||
3966                         strcmp(tokens[9], "digest_size"))
3967                 return NULL;
3968
3969         xform_aead = calloc(1, sizeof(*xform_aead));
3970         if (xform_aead == NULL)
3971                 return NULL;
3972
3973         xform_aead->type = RTE_CRYPTO_SYM_XFORM_AEAD;
3974         xform_aead->aead.op = encrypt ? RTE_CRYPTO_AEAD_OP_ENCRYPT :
3975                         RTE_CRYPTO_AEAD_OP_DECRYPT;
3976
3977         /* aead_algo */
3978         status = rte_cryptodev_get_aead_algo_enum(&xform_aead->aead.algo,
3979                         tokens[2]);
3980         if (status < 0)
3981                 goto error_exit;
3982
3983         /* aead_key */
3984         len = strlen(tokens[4]);
3985         if (len / 2 > max_key_len) {
3986                 status = -ENOMEM;
3987                 goto error_exit;
3988         }
3989
3990         status = parse_hex_string(tokens[4], key, (uint32_t *)&len);
3991         if (status < 0)
3992                 goto error_exit;
3993
3994         xform_aead->aead.key.data = key;
3995         xform_aead->aead.key.length = (uint16_t)len;
3996
3997         /* aead_iv */
3998         len = strlen(tokens[6]);
3999         p->aead.iv.val = calloc(1, len / 2 + 1);
4000         if (p->aead.iv.val == NULL)
4001                 goto error_exit;
4002
4003         status = parse_hex_string(tokens[6], p->aead.iv.val,
4004                         (uint32_t *)&len);
4005         if (status < 0)
4006                 goto error_exit;
4007
4008         xform_aead->aead.iv.length = (uint16_t)len;
4009         xform_aead->aead.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
4010         p->aead.iv.length = (uint32_t)len;
4011
4012         /* aead_aad */
4013         len = strlen(tokens[8]);
4014         p->aead.aad.val = calloc(1, len / 2 + 1);
4015         if (p->aead.aad.val == NULL)
4016                 goto error_exit;
4017
4018         status = parse_hex_string(tokens[8], p->aead.aad.val, (uint32_t *)&len);
4019         if (status < 0)
4020                 goto error_exit;
4021
4022         xform_aead->aead.aad_length = (uint16_t)len;
4023         p->aead.aad.length = (uint32_t)len;
4024
4025         /* digest_size */
4026         status = parser_read_uint16(&xform_aead->aead.digest_length,
4027                         tokens[10]);
4028         if (status < 0)
4029                 goto error_exit;
4030
4031         *used_n_tokens = 11;
4032
4033         return xform_aead;
4034
4035 error_exit:
4036         if (p->aead.iv.val) {
4037                 free(p->aead.iv.val);
4038                 p->aead.iv.val = NULL;
4039         }
4040         if (p->aead.aad.val) {
4041                 free(p->aead.aad.val);
4042                 p->aead.aad.val = NULL;
4043         }
4044
4045         free(xform_aead);
4046
4047         return NULL;
4048 }
4049
4050
4051 static uint32_t
4052 parse_table_action_sym_crypto(char **tokens,
4053         uint32_t n_tokens,
4054         struct table_rule_action *a)
4055 {
4056         struct rte_table_action_sym_crypto_params *p = &a->sym_crypto;
4057         struct rte_crypto_sym_xform *xform = NULL;
4058         uint8_t *key = a->sym_crypto_key;
4059         uint32_t max_key_len = SYM_CRYPTO_MAX_KEY_SIZE;
4060         uint32_t used_n_tokens;
4061         uint32_t encrypt;
4062         int status;
4063
4064         if ((n_tokens < 12) ||
4065                 strcmp(tokens[0], "sym_crypto") ||
4066                 strcmp(tokens[2], "type"))
4067                 return 0;
4068
4069         memset(p, 0, sizeof(*p));
4070
4071         if (strcmp(tokens[1], "encrypt") == 0)
4072                 encrypt = 1;
4073         else
4074                 encrypt = 0;
4075
4076         status = parser_read_uint32(&p->data_offset, tokens[n_tokens - 1]);
4077         if (status < 0)
4078                 return 0;
4079
4080         if (strcmp(tokens[3], "cipher") == 0) {
4081                 tokens += 3;
4082                 n_tokens -= 3;
4083
4084                 xform = parse_table_action_cipher(p, key, max_key_len, tokens,
4085                                 n_tokens, encrypt, &used_n_tokens);
4086         } else if (strcmp(tokens[3], "cipher_auth") == 0) {
4087                 tokens += 3;
4088                 n_tokens -= 3;
4089
4090                 xform = parse_table_action_cipher_auth(p, key, max_key_len,
4091                                 tokens, n_tokens, encrypt, &used_n_tokens);
4092         } else if (strcmp(tokens[3], "aead") == 0) {
4093                 tokens += 3;
4094                 n_tokens -= 3;
4095
4096                 xform = parse_table_action_aead(p, key, max_key_len, tokens,
4097                                 n_tokens, encrypt, &used_n_tokens);
4098         }
4099
4100         if (xform == NULL)
4101                 return 0;
4102
4103         p->xform = xform;
4104
4105         if (strcmp(tokens[used_n_tokens], "data_offset")) {
4106                 parse_free_sym_crypto_param_data(p);
4107                 return 0;
4108         }
4109
4110         a->action_mask |= 1 << RTE_TABLE_ACTION_SYM_CRYPTO;
4111
4112         return used_n_tokens + 5;
4113 }
4114
4115 static uint32_t
4116 parse_table_action_tag(char **tokens,
4117         uint32_t n_tokens,
4118         struct table_rule_action *a)
4119 {
4120         if ((n_tokens < 2) ||
4121                 strcmp(tokens[0], "tag"))
4122                 return 0;
4123
4124         if (parser_read_uint32(&a->tag.tag, tokens[1]))
4125                 return 0;
4126
4127         a->action_mask |= 1 << RTE_TABLE_ACTION_TAG;
4128         return 2;
4129 }
4130
4131 static uint32_t
4132 parse_table_action_decap(char **tokens,
4133         uint32_t n_tokens,
4134         struct table_rule_action *a)
4135 {
4136         if ((n_tokens < 2) ||
4137                 strcmp(tokens[0], "decap"))
4138                 return 0;
4139
4140         if (parser_read_uint16(&a->decap.n, tokens[1]))
4141                 return 0;
4142
4143         a->action_mask |= 1 << RTE_TABLE_ACTION_DECAP;
4144         return 2;
4145 }
4146
4147 static uint32_t
4148 parse_table_action(char **tokens,
4149         uint32_t n_tokens,
4150         char *out,
4151         size_t out_size,
4152         struct table_rule_action *a)
4153 {
4154         uint32_t n_tokens0 = n_tokens;
4155
4156         memset(a, 0, sizeof(*a));
4157
4158         if ((n_tokens < 2) ||
4159                 strcmp(tokens[0], "action"))
4160                 return 0;
4161
4162         tokens++;
4163         n_tokens--;
4164
4165         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
4166                 uint32_t n;
4167
4168                 n = parse_table_action_fwd(tokens, n_tokens, a);
4169                 if (n == 0) {
4170                         snprintf(out, out_size, MSG_ARG_INVALID,
4171                                 "action fwd");
4172                         return 0;
4173                 }
4174
4175                 tokens += n;
4176                 n_tokens -= n;
4177         }
4178
4179         if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
4180                 uint32_t n;
4181
4182                 n = parse_table_action_balance(tokens, n_tokens, a);
4183                 if (n == 0) {
4184                         snprintf(out, out_size, MSG_ARG_INVALID,
4185                                 "action balance");
4186                         return 0;
4187                 }
4188
4189                 tokens += n;
4190                 n_tokens -= n;
4191         }
4192
4193         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
4194                 uint32_t n;
4195
4196                 n = parse_table_action_meter(tokens, n_tokens, a);
4197                 if (n == 0) {
4198                         snprintf(out, out_size, MSG_ARG_INVALID,
4199                                 "action meter");
4200                         return 0;
4201                 }
4202
4203                 tokens += n;
4204                 n_tokens -= n;
4205         }
4206
4207         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
4208                 uint32_t n;
4209
4210                 n = parse_table_action_tm(tokens, n_tokens, a);
4211                 if (n == 0) {
4212                         snprintf(out, out_size, MSG_ARG_INVALID,
4213                                 "action tm");
4214                         return 0;
4215                 }
4216
4217                 tokens += n;
4218                 n_tokens -= n;
4219         }
4220
4221         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
4222                 uint32_t n;
4223
4224                 n = parse_table_action_encap(tokens, n_tokens, a);
4225                 if (n == 0) {
4226                         snprintf(out, out_size, MSG_ARG_INVALID,
4227                                 "action encap");
4228                         return 0;
4229                 }
4230
4231                 tokens += n;
4232                 n_tokens -= n;
4233         }
4234
4235         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
4236                 uint32_t n;
4237
4238                 n = parse_table_action_nat(tokens, n_tokens, a);
4239                 if (n == 0) {
4240                         snprintf(out, out_size, MSG_ARG_INVALID,
4241                                 "action nat");
4242                         return 0;
4243                 }
4244
4245                 tokens += n;
4246                 n_tokens -= n;
4247         }
4248
4249         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
4250                 uint32_t n;
4251
4252                 n = parse_table_action_ttl(tokens, n_tokens, a);
4253                 if (n == 0) {
4254                         snprintf(out, out_size, MSG_ARG_INVALID,
4255                                 "action ttl");
4256                         return 0;
4257                 }
4258
4259                 tokens += n;
4260                 n_tokens -= n;
4261         }
4262
4263         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
4264                 uint32_t n;
4265
4266                 n = parse_table_action_stats(tokens, n_tokens, a);
4267                 if (n == 0) {
4268                         snprintf(out, out_size, MSG_ARG_INVALID,
4269                                 "action stats");
4270                         return 0;
4271                 }
4272
4273                 tokens += n;
4274                 n_tokens -= n;
4275         }
4276
4277         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
4278                 uint32_t n;
4279
4280                 n = parse_table_action_time(tokens, n_tokens, a);
4281                 if (n == 0) {
4282                         snprintf(out, out_size, MSG_ARG_INVALID,
4283                                 "action time");
4284                         return 0;
4285                 }
4286
4287                 tokens += n;
4288                 n_tokens -= n;
4289         }
4290
4291         if (n_tokens && (strcmp(tokens[0], "sym_crypto") == 0)) {
4292                 uint32_t n;
4293
4294                 n = parse_table_action_sym_crypto(tokens, n_tokens, a);
4295                 if (n == 0) {
4296                         snprintf(out, out_size, MSG_ARG_INVALID,
4297                                 "action sym_crypto");
4298                 }
4299
4300                 tokens += n;
4301                 n_tokens -= n;
4302         }
4303
4304         if (n_tokens && (strcmp(tokens[0], "tag") == 0)) {
4305                 uint32_t n;
4306
4307                 n = parse_table_action_tag(tokens, n_tokens, a);
4308                 if (n == 0) {
4309                         snprintf(out, out_size, MSG_ARG_INVALID,
4310                                 "action tag");
4311                         return 0;
4312                 }
4313
4314                 tokens += n;
4315                 n_tokens -= n;
4316         }
4317
4318         if (n_tokens && (strcmp(tokens[0], "decap") == 0)) {
4319                 uint32_t n;
4320
4321                 n = parse_table_action_decap(tokens, n_tokens, a);
4322                 if (n == 0) {
4323                         snprintf(out, out_size, MSG_ARG_INVALID,
4324                                 "action decap");
4325                         return 0;
4326                 }
4327
4328                 tokens += n;
4329                 n_tokens -= n;
4330         }
4331
4332         if (n_tokens0 - n_tokens == 1) {
4333                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
4334                 return 0;
4335         }
4336
4337         return n_tokens0 - n_tokens;
4338 }
4339
4340
4341 static const char cmd_pipeline_table_rule_add_help[] =
4342 "pipeline <pipeline_name> table <table_id> rule add\n"
4343 "     match <match>\n"
4344 "     action <table_action>\n";
4345
4346 static void
4347 cmd_pipeline_table_rule_add(char **tokens,
4348         uint32_t n_tokens,
4349         char *out,
4350         size_t out_size)
4351 {
4352         struct table_rule_match m;
4353         struct table_rule_action a;
4354         char *pipeline_name;
4355         uint32_t table_id, t0, n_tokens_parsed;
4356         int status;
4357
4358         if (n_tokens < 8) {
4359                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4360                 return;
4361         }
4362
4363         pipeline_name = tokens[1];
4364
4365         if (strcmp(tokens[2], "table") != 0) {
4366                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4367                 return;
4368         }
4369
4370         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4371                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4372                 return;
4373         }
4374
4375         if (strcmp(tokens[4], "rule") != 0) {
4376                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4377                 return;
4378         }
4379
4380         if (strcmp(tokens[5], "add") != 0) {
4381                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4382                 return;
4383         }
4384
4385         t0 = 6;
4386
4387         /* match */
4388         n_tokens_parsed = parse_match(tokens + t0,
4389                 n_tokens - t0,
4390                 out,
4391                 out_size,
4392                 &m);
4393         if (n_tokens_parsed == 0)
4394                 return;
4395         t0 += n_tokens_parsed;
4396
4397         /* action */
4398         n_tokens_parsed = parse_table_action(tokens + t0,
4399                 n_tokens - t0,
4400                 out,
4401                 out_size,
4402                 &a);
4403         if (n_tokens_parsed == 0)
4404                 return;
4405         t0 += n_tokens_parsed;
4406
4407         if (t0 != n_tokens) {
4408                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
4409                 return;
4410         }
4411
4412         status = pipeline_table_rule_add(pipeline_name, table_id, &m, &a);
4413         if (status) {
4414                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4415                 return;
4416         }
4417
4418         if (a.action_mask & 1 << RTE_TABLE_ACTION_SYM_CRYPTO)
4419                 parse_free_sym_crypto_param_data(&a.sym_crypto);
4420 }
4421
4422
4423 static const char cmd_pipeline_table_rule_add_default_help[] =
4424 "pipeline <pipeline_name> table <table_id> rule add\n"
4425 "     match\n"
4426 "        default\n"
4427 "     action\n"
4428 "        fwd\n"
4429 "           drop\n"
4430 "           | port <port_id>\n"
4431 "           | meta\n"
4432 "           | table <table_id>\n";
4433
4434 static void
4435 cmd_pipeline_table_rule_add_default(char **tokens,
4436         uint32_t n_tokens,
4437         char *out,
4438         size_t out_size)
4439 {
4440         struct table_rule_action action;
4441         char *pipeline_name;
4442         uint32_t table_id;
4443         int status;
4444
4445         if ((n_tokens != 11) && (n_tokens != 12)) {
4446                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4447                 return;
4448         }
4449
4450         pipeline_name = tokens[1];
4451
4452         if (strcmp(tokens[2], "table") != 0) {
4453                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4454                 return;
4455         }
4456
4457         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4458                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4459                 return;
4460         }
4461
4462         if (strcmp(tokens[4], "rule") != 0) {
4463                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4464                 return;
4465         }
4466
4467         if (strcmp(tokens[5], "add") != 0) {
4468                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4469                 return;
4470         }
4471
4472         if (strcmp(tokens[6], "match") != 0) {
4473                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
4474                 return;
4475         }
4476
4477         if (strcmp(tokens[7], "default") != 0) {
4478                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
4479                 return;
4480         }
4481
4482         if (strcmp(tokens[8], "action") != 0) {
4483                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
4484                 return;
4485         }
4486
4487         if (strcmp(tokens[9], "fwd") != 0) {
4488                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
4489                 return;
4490         }
4491
4492         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
4493
4494         if (strcmp(tokens[10], "drop") == 0) {
4495                 if (n_tokens != 11) {
4496                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4497                         return;
4498                 }
4499
4500                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
4501         } else if (strcmp(tokens[10], "port") == 0) {
4502                 uint32_t id;
4503
4504                 if (n_tokens != 12) {
4505                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4506                         return;
4507                 }
4508
4509                 if (parser_read_uint32(&id, tokens[11]) != 0) {
4510                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
4511                         return;
4512                 }
4513
4514                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
4515                 action.fwd.id = id;
4516         } else if (strcmp(tokens[10], "meta") == 0) {
4517                 if (n_tokens != 11) {
4518                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4519                         return;
4520                 }
4521
4522                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
4523         } else if (strcmp(tokens[10], "table") == 0) {
4524                 uint32_t id;
4525
4526                 if (n_tokens != 12) {
4527                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4528                         return;
4529                 }
4530
4531                 if (parser_read_uint32(&id, tokens[11]) != 0) {
4532                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4533                         return;
4534                 }
4535
4536                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
4537                 action.fwd.id = id;
4538         } else {
4539                 snprintf(out, out_size, MSG_ARG_INVALID,
4540                         "drop or port or meta or table");
4541                 return;
4542         }
4543
4544         status = pipeline_table_rule_add_default(pipeline_name,
4545                 table_id,
4546                 &action);
4547         if (status) {
4548                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4549                 return;
4550         }
4551 }
4552
4553
4554 static const char cmd_pipeline_table_rule_add_bulk_help[] =
4555 "pipeline <pipeline_name> table <table_id> rule add bulk <file_name>\n"
4556 "\n"
4557 "  File <file_name>:\n"
4558 "  - line format: match <match> action <action>\n";
4559
4560 static int
4561 cli_rule_file_process(const char *file_name,
4562         size_t line_len_max,
4563         struct table_rule_list **rule_list,
4564         uint32_t *n_rules,
4565         uint32_t *line_number,
4566         char *out,
4567         size_t out_size);
4568
4569 static void
4570 cmd_pipeline_table_rule_add_bulk(char **tokens,
4571         uint32_t n_tokens,
4572         char *out,
4573         size_t out_size)
4574 {
4575         struct table_rule_list *list = NULL;
4576         char *pipeline_name, *file_name;
4577         uint32_t table_id, n_rules, n_rules_added, n_rules_not_added, line_number;
4578         int status;
4579
4580         if (n_tokens != 8) {
4581                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4582                 return;
4583         }
4584
4585         pipeline_name = tokens[1];
4586
4587         if (strcmp(tokens[2], "table") != 0) {
4588                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4589                 return;
4590         }
4591
4592         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4593                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4594                 return;
4595         }
4596
4597         if (strcmp(tokens[4], "rule") != 0) {
4598                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4599                 return;
4600         }
4601
4602         if (strcmp(tokens[5], "add") != 0) {
4603                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4604                 return;
4605         }
4606
4607         if (strcmp(tokens[6], "bulk") != 0) {
4608                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
4609                 return;
4610         }
4611
4612         file_name = tokens[7];
4613
4614         /* Load rules from file. */
4615         status = cli_rule_file_process(file_name,
4616                 1024,
4617                 &list,
4618                 &n_rules,
4619                 &line_number,
4620                 out,
4621                 out_size);
4622         if (status) {
4623                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4624                 return;
4625         }
4626
4627         /* Rule bulk add */
4628         status = pipeline_table_rule_add_bulk(pipeline_name,
4629                 table_id,
4630                 list,
4631                 &n_rules_added,
4632                 &n_rules_not_added);
4633         if (status) {
4634                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4635                 return;
4636         }
4637
4638         snprintf(out, out_size, "Added %u rules out of %u.\n",
4639                 n_rules_added,
4640                 n_rules);
4641 }
4642
4643
4644 static const char cmd_pipeline_table_rule_delete_help[] =
4645 "pipeline <pipeline_name> table <table_id> rule delete\n"
4646 "     match <match>\n";
4647
4648 static void
4649 cmd_pipeline_table_rule_delete(char **tokens,
4650         uint32_t n_tokens,
4651         char *out,
4652         size_t out_size)
4653 {
4654         struct table_rule_match m;
4655         char *pipeline_name;
4656         uint32_t table_id, n_tokens_parsed, t0;
4657         int status;
4658
4659         if (n_tokens < 8) {
4660                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4661                 return;
4662         }
4663
4664         pipeline_name = tokens[1];
4665
4666         if (strcmp(tokens[2], "table") != 0) {
4667                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4668                 return;
4669         }
4670
4671         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4672                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4673                 return;
4674         }
4675
4676         if (strcmp(tokens[4], "rule") != 0) {
4677                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4678                 return;
4679         }
4680
4681         if (strcmp(tokens[5], "delete") != 0) {
4682                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4683                 return;
4684         }
4685
4686         t0 = 6;
4687
4688         /* match */
4689         n_tokens_parsed = parse_match(tokens + t0,
4690                 n_tokens - t0,
4691                 out,
4692                 out_size,
4693                 &m);
4694         if (n_tokens_parsed == 0)
4695                 return;
4696         t0 += n_tokens_parsed;
4697
4698         if (n_tokens != t0) {
4699                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4700                 return;
4701         }
4702
4703         status = pipeline_table_rule_delete(pipeline_name,
4704                 table_id,
4705                 &m);
4706         if (status) {
4707                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4708                 return;
4709         }
4710 }
4711
4712
4713 static const char cmd_pipeline_table_rule_delete_default_help[] =
4714 "pipeline <pipeline_name> table <table_id> rule delete\n"
4715 "     match\n"
4716 "        default\n";
4717
4718 static void
4719 cmd_pipeline_table_rule_delete_default(char **tokens,
4720         uint32_t n_tokens,
4721         char *out,
4722         size_t out_size)
4723 {
4724         char *pipeline_name;
4725         uint32_t table_id;
4726         int status;
4727
4728         if (n_tokens != 8) {
4729                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4730                 return;
4731         }
4732
4733         pipeline_name = tokens[1];
4734
4735         if (strcmp(tokens[2], "table") != 0) {
4736                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4737                 return;
4738         }
4739
4740         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4741                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4742                 return;
4743         }
4744
4745         if (strcmp(tokens[4], "rule") != 0) {
4746                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4747                 return;
4748         }
4749
4750         if (strcmp(tokens[5], "delete") != 0) {
4751                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4752                 return;
4753         }
4754
4755         if (strcmp(tokens[6], "match") != 0) {
4756                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
4757                 return;
4758         }
4759
4760         if (strcmp(tokens[7], "default") != 0) {
4761                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
4762                 return;
4763         }
4764
4765         status = pipeline_table_rule_delete_default(pipeline_name,
4766                 table_id);
4767         if (status) {
4768                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4769                 return;
4770         }
4771 }
4772
4773 static void
4774 ether_addr_show(FILE *f, struct rte_ether_addr *addr)
4775 {
4776         fprintf(f, "%02x:%02x:%02x:%02x:%02x:%02x",
4777                 (uint32_t)addr->addr_bytes[0], (uint32_t)addr->addr_bytes[1],
4778                 (uint32_t)addr->addr_bytes[2], (uint32_t)addr->addr_bytes[3],
4779                 (uint32_t)addr->addr_bytes[4], (uint32_t)addr->addr_bytes[5]);
4780 }
4781
4782 static void
4783 ipv4_addr_show(FILE *f, uint32_t addr)
4784 {
4785         fprintf(f, "%u.%u.%u.%u",
4786                 addr >> 24,
4787                 (addr >> 16) & 0xFF,
4788                 (addr >> 8) & 0xFF,
4789                 addr & 0xFF);
4790 }
4791
4792 static void
4793 ipv6_addr_show(FILE *f, uint8_t *addr)
4794 {
4795         fprintf(f, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
4796                 "%02x%02x:%02x%02x:%02x%02x:%02x%02x:",
4797                 (uint32_t)addr[0], (uint32_t)addr[1],
4798                 (uint32_t)addr[2], (uint32_t)addr[3],
4799                 (uint32_t)addr[4], (uint32_t)addr[5],
4800                 (uint32_t)addr[6], (uint32_t)addr[7],
4801                 (uint32_t)addr[8], (uint32_t)addr[9],
4802                 (uint32_t)addr[10], (uint32_t)addr[11],
4803                 (uint32_t)addr[12], (uint32_t)addr[13],
4804                 (uint32_t)addr[14], (uint32_t)addr[15]);
4805 }
4806
4807 static const char *
4808 policer_action_string(enum rte_table_action_policer action) {
4809         switch (action) {
4810                 case RTE_TABLE_ACTION_POLICER_COLOR_GREEN: return "G";
4811                 case RTE_TABLE_ACTION_POLICER_COLOR_YELLOW: return "Y";
4812                 case RTE_TABLE_ACTION_POLICER_COLOR_RED: return "R";
4813                 case RTE_TABLE_ACTION_POLICER_DROP: return "D";
4814                 default: return "?";
4815         }
4816 }
4817
4818 static int
4819 table_rule_show(const char *pipeline_name,
4820         uint32_t table_id,
4821         const char *file_name)
4822 {
4823         struct pipeline *p;
4824         struct table *table;
4825         struct table_rule *rule;
4826         FILE *f = NULL;
4827         uint32_t i;
4828
4829         /* Check input params. */
4830         if ((pipeline_name == NULL) ||
4831                 (file_name == NULL))
4832                 return -1;
4833
4834         p = pipeline_find(pipeline_name);
4835         if ((p == NULL) ||
4836                 (table_id >= p->n_tables))
4837                 return -1;
4838
4839         table = &p->table[table_id];
4840
4841         /* Open file. */
4842         f = fopen(file_name, "w");
4843         if (f == NULL)
4844                 return -1;
4845
4846         /* Write table rules to file. */
4847         TAILQ_FOREACH(rule, &table->rules, node) {
4848                 struct table_rule_match *m = &rule->match;
4849                 struct table_rule_action *a = &rule->action;
4850
4851                 fprintf(f, "match ");
4852                 switch (m->match_type) {
4853                 case TABLE_ACL:
4854                         fprintf(f, "acl priority %u ",
4855                                 m->match.acl.priority);
4856
4857                         fprintf(f, m->match.acl.ip_version ? "ipv4 " : "ipv6 ");
4858
4859                         if (m->match.acl.ip_version)
4860                                 ipv4_addr_show(f, m->match.acl.ipv4.sa);
4861                         else
4862                                 ipv6_addr_show(f, m->match.acl.ipv6.sa);
4863
4864                         fprintf(f, "%u",        m->match.acl.sa_depth);
4865
4866                         if (m->match.acl.ip_version)
4867                                 ipv4_addr_show(f, m->match.acl.ipv4.da);
4868                         else
4869                                 ipv6_addr_show(f, m->match.acl.ipv6.da);
4870
4871                         fprintf(f, "%u",        m->match.acl.da_depth);
4872
4873                         fprintf(f, "%u %u %u %u %u ",
4874                                 (uint32_t)m->match.acl.sp0,
4875                                 (uint32_t)m->match.acl.sp1,
4876                                 (uint32_t)m->match.acl.dp0,
4877                                 (uint32_t)m->match.acl.dp1,
4878                                 (uint32_t)m->match.acl.proto);
4879                         break;
4880
4881                 case TABLE_ARRAY:
4882                         fprintf(f, "array %u ",
4883                                 m->match.array.pos);
4884                         break;
4885
4886                 case TABLE_HASH:
4887                         fprintf(f, "hash raw ");
4888                         for (i = 0; i < table->params.match.hash.key_size; i++)
4889                                 fprintf(f, "%02x", m->match.hash.key[i]);
4890                         fprintf(f, " ");
4891                         break;
4892
4893                 case TABLE_LPM:
4894                         fprintf(f, "lpm ");
4895
4896                         fprintf(f, m->match.lpm.ip_version ? "ipv4 " : "ipv6 ");
4897
4898                         if (m->match.acl.ip_version)
4899                                 ipv4_addr_show(f, m->match.lpm.ipv4);
4900                         else
4901                                 ipv6_addr_show(f, m->match.lpm.ipv6);
4902
4903                         fprintf(f, "%u ",
4904                                 (uint32_t)m->match.lpm.depth);
4905                         break;
4906
4907                 default:
4908                         fprintf(f, "unknown ");
4909                 }
4910
4911                 fprintf(f, "action ");
4912                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
4913                         fprintf(f, "fwd ");
4914                         switch (a->fwd.action) {
4915                         case RTE_PIPELINE_ACTION_DROP:
4916                                 fprintf(f, "drop ");
4917                                 break;
4918
4919                         case RTE_PIPELINE_ACTION_PORT:
4920                                 fprintf(f, "port %u ", a->fwd.id);
4921                                 break;
4922
4923                         case RTE_PIPELINE_ACTION_PORT_META:
4924                                 fprintf(f, "meta ");
4925                                 break;
4926
4927                         case RTE_PIPELINE_ACTION_TABLE:
4928                         default:
4929                                 fprintf(f, "table %u ", a->fwd.id);
4930                         }
4931                 }
4932
4933                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
4934                         fprintf(f, "balance ");
4935                         for (i = 0; i < RTE_DIM(a->lb.out); i++)
4936                                 fprintf(f, "%u ", a->lb.out[i]);
4937                 }
4938
4939                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
4940                         fprintf(f, "mtr ");
4941                         for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++)
4942                                 if (a->mtr.tc_mask & (1 << i)) {
4943                                         struct rte_table_action_mtr_tc_params *p =
4944                                                 &a->mtr.mtr[i];
4945                                         enum rte_table_action_policer ga =
4946                                                 p->policer[RTE_COLOR_GREEN];
4947                                         enum rte_table_action_policer ya =
4948                                                 p->policer[RTE_COLOR_YELLOW];
4949                                         enum rte_table_action_policer ra =
4950                                                 p->policer[RTE_COLOR_RED];
4951
4952                                         fprintf(f, "tc%u meter %u policer g %s y %s r %s ",
4953                                                 i,
4954                                                 a->mtr.mtr[i].meter_profile_id,
4955                                                 policer_action_string(ga),
4956                                                 policer_action_string(ya),
4957                                                 policer_action_string(ra));
4958                                 }
4959                 }
4960
4961                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TM))
4962                         fprintf(f, "tm subport %u pipe %u ",
4963                                 a->tm.subport_id,
4964                                 a->tm.pipe_id);
4965
4966                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
4967                         fprintf(f, "encap ");
4968                         switch (a->encap.type) {
4969                         case RTE_TABLE_ACTION_ENCAP_ETHER:
4970                                 fprintf(f, "ether ");
4971                                 ether_addr_show(f, &a->encap.ether.ether.da);
4972                                 fprintf(f, " ");
4973                                 ether_addr_show(f, &a->encap.ether.ether.sa);
4974                                 fprintf(f, " ");
4975                                 break;
4976
4977                         case RTE_TABLE_ACTION_ENCAP_VLAN:
4978                                 fprintf(f, "vlan ");
4979                                 ether_addr_show(f, &a->encap.vlan.ether.da);
4980                                 fprintf(f, " ");
4981                                 ether_addr_show(f, &a->encap.vlan.ether.sa);
4982                                 fprintf(f, " pcp %u dei %u vid %u ",
4983                                         a->encap.vlan.vlan.pcp,
4984                                         a->encap.vlan.vlan.dei,
4985                                         a->encap.vlan.vlan.vid);
4986                                 break;
4987
4988                         case RTE_TABLE_ACTION_ENCAP_QINQ:
4989                                 fprintf(f, "qinq ");
4990                                 ether_addr_show(f, &a->encap.qinq.ether.da);
4991                                 fprintf(f, " ");
4992                                 ether_addr_show(f, &a->encap.qinq.ether.sa);
4993                                 fprintf(f, " pcp %u dei %u vid %u pcp %u dei %u vid %u ",
4994                                         a->encap.qinq.svlan.pcp,
4995                                         a->encap.qinq.svlan.dei,
4996                                         a->encap.qinq.svlan.vid,
4997                                         a->encap.qinq.cvlan.pcp,
4998                                         a->encap.qinq.cvlan.dei,
4999                                         a->encap.qinq.cvlan.vid);
5000                                 break;
5001
5002                         case RTE_TABLE_ACTION_ENCAP_MPLS:
5003                                 fprintf(f, "mpls %s ", (a->encap.mpls.unicast) ?
5004                                         "unicast " : "multicast ");
5005                                 ether_addr_show(f, &a->encap.mpls.ether.da);
5006                                 fprintf(f, " ");
5007                                 ether_addr_show(f, &a->encap.mpls.ether.sa);
5008                                 fprintf(f, " ");
5009                                 for (i = 0; i < a->encap.mpls.mpls_count; i++) {
5010                                         struct rte_table_action_mpls_hdr *l =
5011                                                 &a->encap.mpls.mpls[i];
5012
5013                                         fprintf(f, "label%u %u %u %u ",
5014                                                 i,
5015                                                 l->label,
5016                                                 l->tc,
5017                                                 l->ttl);
5018                                 }
5019                                 break;
5020
5021                         case RTE_TABLE_ACTION_ENCAP_PPPOE:
5022                                 fprintf(f, "pppoe ");
5023                                 ether_addr_show(f, &a->encap.pppoe.ether.da);
5024                                 fprintf(f, " ");
5025                                 ether_addr_show(f, &a->encap.pppoe.ether.sa);
5026                                 fprintf(f, " %u ", a->encap.pppoe.pppoe.session_id);
5027                                 break;
5028
5029                         case RTE_TABLE_ACTION_ENCAP_VXLAN:
5030                                 fprintf(f, "vxlan ether ");
5031                                 ether_addr_show(f, &a->encap.vxlan.ether.da);
5032                                 fprintf(f, " ");
5033                                 ether_addr_show(f, &a->encap.vxlan.ether.sa);
5034                                 if (table->ap->params.encap.vxlan.vlan)
5035                                         fprintf(f, " vlan pcp %u dei %u vid %u ",
5036                                                 a->encap.vxlan.vlan.pcp,
5037                                                 a->encap.vxlan.vlan.dei,
5038                                                 a->encap.vxlan.vlan.vid);
5039                                 if (table->ap->params.encap.vxlan.ip_version) {
5040                                         fprintf(f, " ipv4 ");
5041                                         ipv4_addr_show(f, a->encap.vxlan.ipv4.sa);
5042                                         fprintf(f, " ");
5043                                         ipv4_addr_show(f, a->encap.vxlan.ipv4.da);
5044                                         fprintf(f, " %u %u ",
5045                                                 (uint32_t)a->encap.vxlan.ipv4.dscp,
5046                                                 (uint32_t)a->encap.vxlan.ipv4.ttl);
5047                                 } else {
5048                                         fprintf(f, " ipv6 ");
5049                                         ipv6_addr_show(f, a->encap.vxlan.ipv6.sa);
5050                                         fprintf(f, " ");
5051                                         ipv6_addr_show(f, a->encap.vxlan.ipv6.da);
5052                                         fprintf(f, " %u %u %u ",
5053                                                 a->encap.vxlan.ipv6.flow_label,
5054                                                 (uint32_t)a->encap.vxlan.ipv6.dscp,
5055                                                 (uint32_t)a->encap.vxlan.ipv6.hop_limit);
5056                                         fprintf(f, " udp %u %u vxlan %u ",
5057                                                 a->encap.vxlan.udp.sp,
5058                                                 a->encap.vxlan.udp.dp,
5059                                                 a->encap.vxlan.vxlan.vni);
5060                                 }
5061                                 break;
5062
5063                         default:
5064                                 fprintf(f, "unknown ");
5065                         }
5066                 }
5067
5068                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
5069                         fprintf(f, "nat %s ", (a->nat.ip_version) ? "ipv4 " : "ipv6 ");
5070                         if (a->nat.ip_version)
5071                                 ipv4_addr_show(f, a->nat.addr.ipv4);
5072                         else
5073                                 ipv6_addr_show(f, a->nat.addr.ipv6);
5074                         fprintf(f, " %u ", (uint32_t)(a->nat.port));
5075                 }
5076
5077                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TTL))
5078                         fprintf(f, "ttl %s ", (a->ttl.decrement) ? "dec" : "keep");
5079
5080                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_STATS))
5081                         fprintf(f, "stats ");
5082
5083                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TIME))
5084                         fprintf(f, "time ");
5085
5086                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO))
5087                         fprintf(f, "sym_crypto ");
5088
5089                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TAG))
5090                         fprintf(f, "tag %u ", a->tag.tag);
5091
5092                 if (a->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP))
5093                         fprintf(f, "decap %u ", a->decap.n);
5094
5095                 /* end */
5096                 fprintf(f, "\n");
5097         }
5098
5099         /* Write table default rule to file. */
5100         if (table->rule_default) {
5101                 struct table_rule_action *a = &table->rule_default->action;
5102
5103                 fprintf(f, "# match default action fwd ");
5104
5105                 switch (a->fwd.action) {
5106                 case RTE_PIPELINE_ACTION_DROP:
5107                         fprintf(f, "drop ");
5108                         break;
5109
5110                 case RTE_PIPELINE_ACTION_PORT:
5111                         fprintf(f, "port %u ", a->fwd.id);
5112                         break;
5113
5114                 case RTE_PIPELINE_ACTION_PORT_META:
5115                         fprintf(f, "meta ");
5116                         break;
5117
5118                 case RTE_PIPELINE_ACTION_TABLE:
5119                 default:
5120                         fprintf(f, "table %u ", a->fwd.id);
5121                 }
5122         } else
5123                 fprintf(f, "# match default action fwd drop ");
5124
5125         fprintf(f, "\n");
5126
5127         /* Close file. */
5128         fclose(f);
5129
5130         return 0;
5131 }
5132
5133 static const char cmd_pipeline_table_rule_show_help[] =
5134 "pipeline <pipeline_name> table <table_id> rule show\n"
5135 "     file <file_name>\n";
5136
5137 static void
5138 cmd_pipeline_table_rule_show(char **tokens,
5139         uint32_t n_tokens,
5140         char *out,
5141         size_t out_size)
5142 {
5143         char *file_name = NULL, *pipeline_name;
5144         uint32_t table_id;
5145         int status;
5146
5147         if (n_tokens != 8) {
5148                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5149                 return;
5150         }
5151
5152         pipeline_name = tokens[1];
5153
5154         if (strcmp(tokens[2], "table") != 0) {
5155                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5156                 return;
5157         }
5158
5159         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5160                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5161                 return;
5162         }
5163
5164         if (strcmp(tokens[4], "rule") != 0) {
5165                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5166                 return;
5167         }
5168
5169         if (strcmp(tokens[5], "show") != 0) {
5170                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "show");
5171                 return;
5172         }
5173
5174         if (strcmp(tokens[6], "file") != 0) {
5175                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "file");
5176                 return;
5177         }
5178
5179         file_name = tokens[7];
5180
5181         status = table_rule_show(pipeline_name, table_id, file_name);
5182         if (status) {
5183                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5184                 return;
5185         }
5186 }
5187
5188 static const char cmd_pipeline_table_rule_stats_read_help[] =
5189 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n"
5190 "     match <match>\n";
5191
5192 static void
5193 cmd_pipeline_table_rule_stats_read(char **tokens,
5194         uint32_t n_tokens,
5195         char *out,
5196         size_t out_size)
5197 {
5198         struct table_rule_match m;
5199         struct rte_table_action_stats_counters stats;
5200         char *pipeline_name;
5201         uint32_t table_id, n_tokens_parsed;
5202         int clear = 0, status;
5203
5204         if (n_tokens < 7) {
5205                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5206                 return;
5207         }
5208
5209         pipeline_name = tokens[1];
5210
5211         if (strcmp(tokens[2], "table") != 0) {
5212                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5213                 return;
5214         }
5215
5216         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5217                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5218                 return;
5219         }
5220
5221         if (strcmp(tokens[4], "rule") != 0) {
5222                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5223                 return;
5224         }
5225
5226         if (strcmp(tokens[5], "read") != 0) {
5227                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5228                 return;
5229         }
5230
5231         if (strcmp(tokens[6], "stats") != 0) {
5232                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
5233                 return;
5234         }
5235
5236         n_tokens -= 7;
5237         tokens += 7;
5238
5239         /* clear */
5240         if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5241                 clear = 1;
5242
5243                 n_tokens--;
5244                 tokens++;
5245         }
5246
5247         /* match */
5248         if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5249                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5250                 return;
5251         }
5252
5253         n_tokens_parsed = parse_match(tokens,
5254                 n_tokens,
5255                 out,
5256                 out_size,
5257                 &m);
5258         if (n_tokens_parsed == 0)
5259                 return;
5260         n_tokens -= n_tokens_parsed;
5261         tokens += n_tokens_parsed;
5262
5263         /* end */
5264         if (n_tokens) {
5265                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5266                 return;
5267         }
5268
5269         /* Read table rule stats. */
5270         status = pipeline_table_rule_stats_read(pipeline_name,
5271                 table_id,
5272                 &m,
5273                 &stats,
5274                 clear);
5275         if (status) {
5276                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5277                 return;
5278         }
5279
5280         /* Print stats. */
5281         if (stats.n_packets_valid && stats.n_bytes_valid)
5282                 snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: %" PRIu64 "\n",
5283                         stats.n_packets,
5284                         stats.n_bytes);
5285
5286         if (stats.n_packets_valid && !stats.n_bytes_valid)
5287                 snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: N/A\n",
5288                         stats.n_packets);
5289
5290         if (!stats.n_packets_valid && stats.n_bytes_valid)
5291                 snprintf(out, out_size, "Packets: N/A; Bytes: %" PRIu64 "\n",
5292                         stats.n_bytes);
5293
5294         if (!stats.n_packets_valid && !stats.n_bytes_valid)
5295                 snprintf(out, out_size, "Packets: N/A ; Bytes: N/A\n");
5296 }
5297
5298 static const char cmd_pipeline_table_meter_profile_add_help[] =
5299 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n"
5300 "   add srtcm cir <cir> cbs <cbs> ebs <ebs>\n"
5301 "   | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
5302
5303 static void
5304 cmd_pipeline_table_meter_profile_add(char **tokens,
5305         uint32_t n_tokens,
5306         char *out,
5307         size_t out_size)
5308 {
5309         struct rte_table_action_meter_profile p;
5310         char *pipeline_name;
5311         uint32_t table_id, meter_profile_id;
5312         int status;
5313
5314         if (n_tokens < 9) {
5315                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5316                 return;
5317         }
5318
5319         pipeline_name = tokens[1];
5320
5321         if (strcmp(tokens[2], "table") != 0) {
5322                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5323                 return;
5324         }
5325
5326         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5327                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5328                 return;
5329         }
5330
5331         if (strcmp(tokens[4], "meter") != 0) {
5332                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5333                 return;
5334         }
5335
5336         if (strcmp(tokens[5], "profile") != 0) {
5337                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5338                 return;
5339         }
5340
5341         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5342                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5343                 return;
5344         }
5345
5346         if (strcmp(tokens[7], "add") != 0) {
5347                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
5348                 return;
5349         }
5350
5351         if (strcmp(tokens[8], "srtcm") == 0) {
5352                 if (n_tokens != 15) {
5353                         snprintf(out, out_size, MSG_ARG_MISMATCH,
5354                                 tokens[0]);
5355                         return;
5356                 }
5357
5358                 p.alg = RTE_TABLE_ACTION_METER_SRTCM;
5359
5360                 if (strcmp(tokens[9], "cir") != 0) {
5361                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5362                         return;
5363                 }
5364
5365                 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
5366                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5367                         return;
5368                 }
5369
5370                 if (strcmp(tokens[11], "cbs") != 0) {
5371                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5372                         return;
5373                 }
5374
5375                 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
5376                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5377                         return;
5378                 }
5379
5380                 if (strcmp(tokens[13], "ebs") != 0) {
5381                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
5382                         return;
5383                 }
5384
5385                 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
5386                         snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
5387                         return;
5388                 }
5389         } else if (strcmp(tokens[8], "trtcm") == 0) {
5390                 if (n_tokens != 17) {
5391                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5392                         return;
5393                 }
5394
5395                 p.alg = RTE_TABLE_ACTION_METER_TRTCM;
5396
5397                 if (strcmp(tokens[9], "cir") != 0) {
5398                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5399                         return;
5400                 }
5401
5402                 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
5403                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5404                         return;
5405                 }
5406
5407                 if (strcmp(tokens[11], "pir") != 0) {
5408                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
5409                         return;
5410                 }
5411
5412                 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
5413                         snprintf(out, out_size, MSG_ARG_INVALID, "pir");
5414                         return;
5415                 }
5416                 if (strcmp(tokens[13], "cbs") != 0) {
5417                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5418                         return;
5419                 }
5420
5421                 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
5422                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5423                         return;
5424                 }
5425
5426                 if (strcmp(tokens[15], "pbs") != 0) {
5427                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
5428                         return;
5429                 }
5430
5431                 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
5432                         snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
5433                         return;
5434                 }
5435         } else {
5436                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5437                 return;
5438         }
5439
5440         status = pipeline_table_mtr_profile_add(pipeline_name,
5441                 table_id,
5442                 meter_profile_id,
5443                 &p);
5444         if (status) {
5445                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5446                 return;
5447         }
5448 }
5449
5450
5451 static const char cmd_pipeline_table_meter_profile_delete_help[] =
5452 "pipeline <pipeline_name> table <table_id>\n"
5453 "   meter profile <meter_profile_id> delete\n";
5454
5455 static void
5456 cmd_pipeline_table_meter_profile_delete(char **tokens,
5457         uint32_t n_tokens,
5458         char *out,
5459         size_t out_size)
5460 {
5461         char *pipeline_name;
5462         uint32_t table_id, meter_profile_id;
5463         int status;
5464
5465         if (n_tokens != 8) {
5466                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5467                 return;
5468         }
5469
5470         pipeline_name = tokens[1];
5471
5472         if (strcmp(tokens[2], "table") != 0) {
5473                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5474                 return;
5475         }
5476
5477         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5478                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5479                 return;
5480         }
5481
5482         if (strcmp(tokens[4], "meter") != 0) {
5483                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5484                 return;
5485         }
5486
5487         if (strcmp(tokens[5], "profile") != 0) {
5488                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5489                 return;
5490         }
5491
5492         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5493                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5494                 return;
5495         }
5496
5497         if (strcmp(tokens[7], "delete") != 0) {
5498                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5499                 return;
5500         }
5501
5502         status = pipeline_table_mtr_profile_delete(pipeline_name,
5503                 table_id,
5504                 meter_profile_id);
5505         if (status) {
5506                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5507                 return;
5508         }
5509 }
5510
5511
5512 static const char cmd_pipeline_table_rule_meter_read_help[] =
5513 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n"
5514 "     match <match>\n";
5515
5516 static void
5517 cmd_pipeline_table_rule_meter_read(char **tokens,
5518         uint32_t n_tokens,
5519         char *out,
5520         size_t out_size)
5521 {
5522         struct table_rule_match m;
5523         struct rte_table_action_mtr_counters stats;
5524         char *pipeline_name;
5525         uint32_t table_id, n_tokens_parsed;
5526         int clear = 0, status;
5527
5528         if (n_tokens < 7) {
5529                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5530                 return;
5531         }
5532
5533         pipeline_name = tokens[1];
5534
5535         if (strcmp(tokens[2], "table") != 0) {
5536                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5537                 return;
5538         }
5539
5540         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5541                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5542                 return;
5543         }
5544
5545         if (strcmp(tokens[4], "rule") != 0) {
5546                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5547                 return;
5548         }
5549
5550         if (strcmp(tokens[5], "read") != 0) {
5551                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5552                 return;
5553         }
5554
5555         if (strcmp(tokens[6], "meter") != 0) {
5556                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5557                 return;
5558         }
5559
5560         n_tokens -= 7;
5561         tokens += 7;
5562
5563         /* clear */
5564         if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5565                 clear = 1;
5566
5567                 n_tokens--;
5568                 tokens++;
5569         }
5570
5571         /* match */
5572         if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5573                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5574                 return;
5575         }
5576
5577         n_tokens_parsed = parse_match(tokens,
5578                 n_tokens,
5579                 out,
5580                 out_size,
5581                 &m);
5582         if (n_tokens_parsed == 0)
5583                 return;
5584         n_tokens -= n_tokens_parsed;
5585         tokens += n_tokens_parsed;
5586
5587         /* end */
5588         if (n_tokens) {
5589                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5590                 return;
5591         }
5592
5593         /* Read table rule meter stats. */
5594         status = pipeline_table_rule_mtr_read(pipeline_name,
5595                 table_id,
5596                 &m,
5597                 &stats,
5598                 clear);
5599         if (status) {
5600                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5601                 return;
5602         }
5603
5604         /* Print stats. */
5605 }
5606
5607
5608 static const char cmd_pipeline_table_dscp_help[] =
5609 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n"
5610 "\n"
5611 " File <file_name>:\n"
5612 "   - exactly 64 lines\n"
5613 "   - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n";
5614
5615 static int
5616 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
5617         const char *file_name,
5618         uint32_t *line_number)
5619 {
5620         FILE *f = NULL;
5621         uint32_t dscp, l;
5622
5623         /* Check input arguments */
5624         if ((dscp_table == NULL) ||
5625                 (file_name == NULL) ||
5626                 (line_number == NULL)) {
5627                 if (line_number)
5628                         *line_number = 0;
5629                 return -EINVAL;
5630         }
5631
5632         /* Open input file */
5633         f = fopen(file_name, "r");
5634         if (f == NULL) {
5635                 *line_number = 0;
5636                 return -EINVAL;
5637         }
5638
5639         /* Read file */
5640         for (dscp = 0, l = 1; ; l++) {
5641                 char line[64];
5642                 char *tokens[3];
5643                 enum rte_color color;
5644                 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
5645
5646                 if (fgets(line, sizeof(line), f) == NULL)
5647                         break;
5648
5649                 if (is_comment(line))
5650                         continue;
5651
5652                 if (parse_tokenize_string(line, tokens, &n_tokens)) {
5653                         *line_number = l;
5654                         fclose(f);
5655                         return -EINVAL;
5656                 }
5657
5658                 if (n_tokens == 0)
5659                         continue;
5660
5661                 if ((dscp >= RTE_DIM(dscp_table->entry)) ||
5662                         (n_tokens != RTE_DIM(tokens)) ||
5663                         parser_read_uint32(&tc_id, tokens[0]) ||
5664                         (tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
5665                         parser_read_uint32(&tc_queue_id, tokens[1]) ||
5666                         (tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
5667                         (strlen(tokens[2]) != 1)) {
5668                         *line_number = l;
5669                         fclose(f);
5670                         return -EINVAL;
5671                 }
5672
5673                 switch (tokens[2][0]) {
5674                 case 'g':
5675                 case 'G':
5676                         color = RTE_COLOR_GREEN;
5677                         break;
5678
5679                 case 'y':
5680                 case 'Y':
5681                         color = RTE_COLOR_YELLOW;
5682                         break;
5683
5684                 case 'r':
5685                 case 'R':
5686                         color = RTE_COLOR_RED;
5687                         break;
5688
5689                 default:
5690                         *line_number = l;
5691                         fclose(f);
5692                         return -EINVAL;
5693                 }
5694
5695                 dscp_table->entry[dscp].tc_id = tc_id;
5696                 dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
5697                 dscp_table->entry[dscp].color = color;
5698                 dscp++;
5699         }
5700
5701         /* Close file */
5702         fclose(f);
5703         return 0;
5704 }
5705
5706 static void
5707 cmd_pipeline_table_dscp(char **tokens,
5708         uint32_t n_tokens,
5709         char *out,
5710         size_t out_size)
5711 {
5712         struct rte_table_action_dscp_table dscp_table;
5713         char *pipeline_name, *file_name;
5714         uint32_t table_id, line_number;
5715         int status;
5716
5717         if (n_tokens != 6) {
5718                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5719                 return;
5720         }
5721
5722         pipeline_name = tokens[1];
5723
5724         if (strcmp(tokens[2], "table") != 0) {
5725                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5726                 return;
5727         }
5728
5729         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5730                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5731                 return;
5732         }
5733
5734         if (strcmp(tokens[4], "dscp") != 0) {
5735                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
5736                 return;
5737         }
5738
5739         file_name = tokens[5];
5740
5741         status = load_dscp_table(&dscp_table, file_name, &line_number);
5742         if (status) {
5743                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
5744                 return;
5745         }
5746
5747         status = pipeline_table_dscp_table_update(pipeline_name,
5748                 table_id,
5749                 UINT64_MAX,
5750                 &dscp_table);
5751         if (status) {
5752                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5753                 return;
5754         }
5755 }
5756
5757
5758 static const char cmd_pipeline_table_rule_ttl_read_help[] =
5759 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n"
5760 "     match <match>\n";
5761
5762 static void
5763 cmd_pipeline_table_rule_ttl_read(char **tokens,
5764         uint32_t n_tokens,
5765         char *out,
5766         size_t out_size)
5767 {
5768         struct table_rule_match m;
5769         struct rte_table_action_ttl_counters stats;
5770         char *pipeline_name;
5771         uint32_t table_id, n_tokens_parsed;
5772         int clear = 0, status;
5773
5774         if (n_tokens < 7) {
5775                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5776                 return;
5777         }
5778
5779         pipeline_name = tokens[1];
5780
5781         if (strcmp(tokens[2], "table") != 0) {
5782                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5783                 return;
5784         }
5785
5786         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5787                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5788                 return;
5789         }
5790
5791         if (strcmp(tokens[4], "rule") != 0) {
5792                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5793                 return;
5794         }
5795
5796         if (strcmp(tokens[5], "read") != 0) {
5797                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5798                 return;
5799         }
5800
5801         if (strcmp(tokens[6], "ttl") != 0) {
5802                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ttl");
5803                 return;
5804         }
5805
5806         n_tokens -= 7;
5807         tokens += 7;
5808
5809         /* clear */
5810         if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5811                 clear = 1;
5812
5813                 n_tokens--;
5814                 tokens++;
5815         }
5816
5817         /* match */
5818         if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5819                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5820                 return;
5821         }
5822
5823         n_tokens_parsed = parse_match(tokens,
5824                 n_tokens,
5825                 out,
5826                 out_size,
5827                 &m);
5828         if (n_tokens_parsed == 0)
5829                 return;
5830         n_tokens -= n_tokens_parsed;
5831         tokens += n_tokens_parsed;
5832
5833         /* end */
5834         if (n_tokens) {
5835                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5836                 return;
5837         }
5838
5839         /* Read table rule TTL stats. */
5840         status = pipeline_table_rule_ttl_read(pipeline_name,
5841                 table_id,
5842                 &m,
5843                 &stats,
5844                 clear);
5845         if (status) {
5846                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5847                 return;
5848         }
5849
5850         /* Print stats. */
5851         snprintf(out, out_size, "Packets: %" PRIu64 "\n",
5852                 stats.n_packets);
5853 }
5854
5855 static const char cmd_pipeline_table_rule_time_read_help[] =
5856 "pipeline <pipeline_name> table <table_id> rule read time\n"
5857 "     match <match>\n";
5858
5859 static void
5860 cmd_pipeline_table_rule_time_read(char **tokens,
5861         uint32_t n_tokens,
5862         char *out,
5863         size_t out_size)
5864 {
5865         struct table_rule_match m;
5866         char *pipeline_name;
5867         uint64_t timestamp;
5868         uint32_t table_id, n_tokens_parsed;
5869         int status;
5870
5871         if (n_tokens < 7) {
5872                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5873                 return;
5874         }
5875
5876         pipeline_name = tokens[1];
5877
5878         if (strcmp(tokens[2], "table") != 0) {
5879                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5880                 return;
5881         }
5882
5883         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5884                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5885                 return;
5886         }
5887
5888         if (strcmp(tokens[4], "rule") != 0) {
5889                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5890                 return;
5891         }
5892
5893         if (strcmp(tokens[5], "read") != 0) {
5894                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5895                 return;
5896         }
5897
5898         if (strcmp(tokens[6], "time") != 0) {
5899                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "time");
5900                 return;
5901         }
5902
5903         n_tokens -= 7;
5904         tokens += 7;
5905
5906         /* match */
5907         if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5908                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5909                 return;
5910         }
5911
5912         n_tokens_parsed = parse_match(tokens,
5913                 n_tokens,
5914                 out,
5915                 out_size,
5916                 &m);
5917         if (n_tokens_parsed == 0)
5918                 return;
5919         n_tokens -= n_tokens_parsed;
5920         tokens += n_tokens_parsed;
5921
5922         /* end */
5923         if (n_tokens) {
5924                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5925                 return;
5926         }
5927
5928         /* Read table rule timestamp. */
5929         status = pipeline_table_rule_time_read(pipeline_name,
5930                 table_id,
5931                 &m,
5932                 &timestamp);
5933         if (status) {
5934                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5935                 return;
5936         }
5937
5938         /* Print stats. */
5939         snprintf(out, out_size, "Packets: %" PRIu64 "\n", timestamp);
5940 }
5941
5942 static const char cmd_thread_pipeline_enable_help[] =
5943 "thread <thread_id> pipeline <pipeline_name> enable\n";
5944
5945 static void
5946 cmd_thread_pipeline_enable(char **tokens,
5947         uint32_t n_tokens,
5948         char *out,
5949         size_t out_size)
5950 {
5951         char *pipeline_name;
5952         uint32_t thread_id;
5953         int status;
5954
5955         if (n_tokens != 5) {
5956                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5957                 return;
5958         }
5959
5960         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5961                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5962                 return;
5963         }
5964
5965         if (strcmp(tokens[2], "pipeline") != 0) {
5966                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5967                 return;
5968         }
5969
5970         pipeline_name = tokens[3];
5971
5972         if (strcmp(tokens[4], "enable") != 0) {
5973                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
5974                 return;
5975         }
5976
5977         status = thread_pipeline_enable(thread_id, pipeline_name);
5978         if (status) {
5979                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
5980                 return;
5981         }
5982 }
5983
5984
5985 static const char cmd_thread_pipeline_disable_help[] =
5986 "thread <thread_id> pipeline <pipeline_name> disable\n";
5987
5988 static void
5989 cmd_thread_pipeline_disable(char **tokens,
5990         uint32_t n_tokens,
5991         char *out,
5992         size_t out_size)
5993 {
5994         char *pipeline_name;
5995         uint32_t thread_id;
5996         int status;
5997
5998         if (n_tokens != 5) {
5999                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
6000                 return;
6001         }
6002
6003         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
6004                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
6005                 return;
6006         }
6007
6008         if (strcmp(tokens[2], "pipeline") != 0) {
6009                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
6010                 return;
6011         }
6012
6013         pipeline_name = tokens[3];
6014
6015         if (strcmp(tokens[4], "disable") != 0) {
6016                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
6017                 return;
6018         }
6019
6020         status = thread_pipeline_disable(thread_id, pipeline_name);
6021         if (status) {
6022                 snprintf(out, out_size, MSG_CMD_FAIL,
6023                         "thread pipeline disable");
6024                 return;
6025         }
6026 }
6027
6028 static void
6029 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
6030 {
6031         tokens++;
6032         n_tokens--;
6033
6034         if (n_tokens == 0) {
6035                 snprintf(out, out_size,
6036                         "Type 'help <command>' for details on each command.\n\n"
6037                         "List of commands:\n"
6038                         "\tmempool\n"
6039                         "\tlink\n"
6040                         "\tswq\n"
6041                         "\ttmgr subport profile\n"
6042                         "\ttmgr pipe profile\n"
6043                         "\ttmgr\n"
6044                         "\ttmgr subport\n"
6045                         "\ttmgr subport pipe\n"
6046                         "\ttap\n"
6047                         "\tkni\n"
6048                         "\tport in action profile\n"
6049                         "\ttable action profile\n"
6050                         "\tpipeline\n"
6051                         "\tpipeline port in\n"
6052                         "\tpipeline port out\n"
6053                         "\tpipeline table\n"
6054                         "\tpipeline port in table\n"
6055                         "\tpipeline port in stats\n"
6056                         "\tpipeline port in enable\n"
6057                         "\tpipeline port in disable\n"
6058                         "\tpipeline port out stats\n"
6059                         "\tpipeline table stats\n"
6060                         "\tpipeline table rule add\n"
6061                         "\tpipeline table rule add default\n"
6062                         "\tpipeline table rule add bulk\n"
6063                         "\tpipeline table rule delete\n"
6064                         "\tpipeline table rule delete default\n"
6065                         "\tpipeline table rule show\n"
6066                         "\tpipeline table rule stats read\n"
6067                         "\tpipeline table meter profile add\n"
6068                         "\tpipeline table meter profile delete\n"
6069                         "\tpipeline table rule meter read\n"
6070                         "\tpipeline table dscp\n"
6071                         "\tpipeline table rule ttl read\n"
6072                         "\tpipeline table rule time read\n"
6073                         "\tthread pipeline enable\n"
6074                         "\tthread pipeline disable\n\n");
6075                 return;
6076         }
6077
6078         if (strcmp(tokens[0], "mempool") == 0) {
6079                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
6080                 return;
6081         }
6082
6083         if (strcmp(tokens[0], "link") == 0) {
6084                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
6085                 return;
6086         }
6087
6088         if (strcmp(tokens[0], "swq") == 0) {
6089                 snprintf(out, out_size, "\n%s\n", cmd_swq_help);
6090                 return;
6091         }
6092
6093         if (strcmp(tokens[0], "tmgr") == 0) {
6094                 if (n_tokens == 1) {
6095                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_help);
6096                         return;
6097                 }
6098
6099                 if ((n_tokens == 2) &&
6100                         (strcmp(tokens[1], "subport")) == 0) {
6101                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help);
6102                         return;
6103                 }
6104
6105                 if ((n_tokens == 3) &&
6106                         (strcmp(tokens[1], "subport") == 0) &&
6107                         (strcmp(tokens[2], "profile") == 0)) {
6108                         snprintf(out, out_size, "\n%s\n",
6109                                 cmd_tmgr_subport_profile_help);
6110                         return;
6111                 }
6112
6113                 if ((n_tokens == 3) &&
6114                         (strcmp(tokens[1], "subport") == 0) &&
6115                         (strcmp(tokens[2], "pipe") == 0)) {
6116                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help);
6117                         return;
6118                 }
6119
6120                 if ((n_tokens == 3) &&
6121                         (strcmp(tokens[1], "pipe") == 0) &&
6122                         (strcmp(tokens[2], "profile") == 0)) {
6123                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help);
6124                         return;
6125                 }
6126         }
6127
6128         if (strcmp(tokens[0], "tap") == 0) {
6129                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
6130                 return;
6131         }
6132
6133         if (strcmp(tokens[0], "kni") == 0) {
6134                 snprintf(out, out_size, "\n%s\n", cmd_kni_help);
6135                 return;
6136         }
6137
6138         if (strcmp(tokens[0], "cryptodev") == 0) {
6139                 snprintf(out, out_size, "\n%s\n", cmd_cryptodev_help);
6140                 return;
6141         }
6142
6143         if ((n_tokens == 4) &&
6144                 (strcmp(tokens[0], "port") == 0) &&
6145                 (strcmp(tokens[1], "in") == 0) &&
6146                 (strcmp(tokens[2], "action") == 0) &&
6147                 (strcmp(tokens[3], "profile") == 0)) {
6148                 snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help);
6149                 return;
6150         }
6151
6152         if ((n_tokens == 3) &&
6153                 (strcmp(tokens[0], "table") == 0) &&
6154                 (strcmp(tokens[1], "action") == 0) &&
6155                 (strcmp(tokens[2], "profile") == 0)) {
6156                 snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help);
6157                 return;
6158         }
6159
6160         if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) {
6161                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_help);
6162                 return;
6163         }
6164
6165         if ((strcmp(tokens[0], "pipeline") == 0) &&
6166                 (strcmp(tokens[1], "port") == 0)) {
6167                 if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) {
6168                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help);
6169                         return;
6170                 }
6171
6172                 if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) {
6173                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help);
6174                         return;
6175                 }
6176
6177                 if ((n_tokens == 4) &&
6178                         (strcmp(tokens[2], "in") == 0) &&
6179                         (strcmp(tokens[3], "table") == 0)) {
6180                         snprintf(out, out_size, "\n%s\n",
6181                                 cmd_pipeline_port_in_table_help);
6182                         return;
6183                 }
6184
6185                 if ((n_tokens == 4) &&
6186                         (strcmp(tokens[2], "in") == 0) &&
6187                         (strcmp(tokens[3], "stats") == 0)) {
6188                         snprintf(out, out_size, "\n%s\n",
6189                                 cmd_pipeline_port_in_stats_help);
6190                         return;
6191                 }
6192
6193                 if ((n_tokens == 4) &&
6194                         (strcmp(tokens[2], "in") == 0) &&
6195                         (strcmp(tokens[3], "enable") == 0)) {
6196                         snprintf(out, out_size, "\n%s\n",
6197                                 cmd_pipeline_port_in_enable_help);
6198                         return;
6199                 }
6200
6201                 if ((n_tokens == 4) &&
6202                         (strcmp(tokens[2], "in") == 0) &&
6203                         (strcmp(tokens[3], "disable") == 0)) {
6204                         snprintf(out, out_size, "\n%s\n",
6205                                 cmd_pipeline_port_in_disable_help);
6206                         return;
6207                 }
6208
6209                 if ((n_tokens == 4) &&
6210                         (strcmp(tokens[2], "out") == 0) &&
6211                         (strcmp(tokens[3], "stats") == 0)) {
6212                         snprintf(out, out_size, "\n%s\n",
6213                                 cmd_pipeline_port_out_stats_help);
6214                         return;
6215                 }
6216         }
6217
6218         if ((strcmp(tokens[0], "pipeline") == 0) &&
6219                 (strcmp(tokens[1], "table") == 0)) {
6220                 if (n_tokens == 2) {
6221                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help);
6222                         return;
6223                 }
6224
6225                 if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) {
6226                         snprintf(out, out_size, "\n%s\n",
6227                                 cmd_pipeline_table_stats_help);
6228                         return;
6229                 }
6230
6231                 if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) {
6232                         snprintf(out, out_size, "\n%s\n",
6233                                 cmd_pipeline_table_dscp_help);
6234                         return;
6235                 }
6236
6237                 if ((n_tokens == 4) &&
6238                         (strcmp(tokens[2], "rule") == 0) &&
6239                         (strcmp(tokens[3], "add") == 0)) {
6240                         snprintf(out, out_size, "\n%s\n",
6241                                 cmd_pipeline_table_rule_add_help);
6242                         return;
6243                 }
6244
6245                 if ((n_tokens == 5) &&
6246                         (strcmp(tokens[2], "rule") == 0) &&
6247                         (strcmp(tokens[3], "add") == 0) &&
6248                         (strcmp(tokens[4], "default") == 0)) {
6249                         snprintf(out, out_size, "\n%s\n",
6250                                 cmd_pipeline_table_rule_add_default_help);
6251                         return;
6252                 }
6253
6254                 if ((n_tokens == 5) &&
6255                         (strcmp(tokens[2], "rule") == 0) &&
6256                         (strcmp(tokens[3], "add") == 0) &&
6257                         (strcmp(tokens[4], "bulk") == 0)) {
6258                         snprintf(out, out_size, "\n%s\n",
6259                                 cmd_pipeline_table_rule_add_bulk_help);
6260                         return;
6261                 }
6262
6263                 if ((n_tokens == 4) &&
6264                         (strcmp(tokens[2], "rule") == 0) &&
6265                         (strcmp(tokens[3], "delete") == 0)) {
6266                         snprintf(out, out_size, "\n%s\n",
6267                                 cmd_pipeline_table_rule_delete_help);
6268                         return;
6269                 }
6270
6271                 if ((n_tokens == 5) &&
6272                         (strcmp(tokens[2], "rule") == 0) &&
6273                         (strcmp(tokens[3], "delete") == 0) &&
6274                         (strcmp(tokens[4], "default") == 0)) {
6275                         snprintf(out, out_size, "\n%s\n",
6276                                 cmd_pipeline_table_rule_delete_default_help);
6277                         return;
6278                 }
6279
6280                 if ((n_tokens == 4) &&
6281                         (strcmp(tokens[2], "rule") == 0) &&
6282                         (strcmp(tokens[3], "show") == 0)) {
6283                         snprintf(out, out_size, "\n%s\n",
6284                                 cmd_pipeline_table_rule_show_help);
6285                         return;
6286                 }
6287
6288                 if ((n_tokens == 5) &&
6289                         (strcmp(tokens[2], "rule") == 0) &&
6290                         (strcmp(tokens[3], "stats") == 0) &&
6291                         (strcmp(tokens[4], "read") == 0)) {
6292                         snprintf(out, out_size, "\n%s\n",
6293                                 cmd_pipeline_table_rule_stats_read_help);
6294                         return;
6295                 }
6296
6297                 if ((n_tokens == 5) &&
6298                         (strcmp(tokens[2], "meter") == 0) &&
6299                         (strcmp(tokens[3], "profile") == 0) &&
6300                         (strcmp(tokens[4], "add") == 0)) {
6301                         snprintf(out, out_size, "\n%s\n",
6302                                 cmd_pipeline_table_meter_profile_add_help);
6303                         return;
6304                 }
6305
6306                 if ((n_tokens == 5) &&
6307                         (strcmp(tokens[2], "meter") == 0) &&
6308                         (strcmp(tokens[3], "profile") == 0) &&
6309                         (strcmp(tokens[4], "delete") == 0)) {
6310                         snprintf(out, out_size, "\n%s\n",
6311                                 cmd_pipeline_table_meter_profile_delete_help);
6312                         return;
6313                 }
6314
6315                 if ((n_tokens == 5) &&
6316                         (strcmp(tokens[2], "rule") == 0) &&
6317                         (strcmp(tokens[3], "meter") == 0) &&
6318                         (strcmp(tokens[4], "read") == 0)) {
6319                         snprintf(out, out_size, "\n%s\n",
6320                                 cmd_pipeline_table_rule_meter_read_help);
6321                         return;
6322                 }
6323
6324                 if ((n_tokens == 5) &&
6325                         (strcmp(tokens[2], "rule") == 0) &&
6326                         (strcmp(tokens[3], "ttl") == 0) &&
6327                         (strcmp(tokens[4], "read") == 0)) {
6328                         snprintf(out, out_size, "\n%s\n",
6329                                 cmd_pipeline_table_rule_ttl_read_help);
6330                         return;
6331                 }
6332
6333                 if ((n_tokens == 5) &&
6334                         (strcmp(tokens[2], "rule") == 0) &&
6335                         (strcmp(tokens[3], "time") == 0) &&
6336                         (strcmp(tokens[4], "read") == 0)) {
6337                         snprintf(out, out_size, "\n%s\n",
6338                                 cmd_pipeline_table_rule_time_read_help);
6339                         return;
6340                 }
6341         }
6342
6343         if ((n_tokens == 3) &&
6344                 (strcmp(tokens[0], "thread") == 0) &&
6345                 (strcmp(tokens[1], "pipeline") == 0)) {
6346                 if (strcmp(tokens[2], "enable") == 0) {
6347                         snprintf(out, out_size, "\n%s\n",
6348                                 cmd_thread_pipeline_enable_help);
6349                         return;
6350                 }
6351
6352                 if (strcmp(tokens[2], "disable") == 0) {
6353                         snprintf(out, out_size, "\n%s\n",
6354                                 cmd_thread_pipeline_disable_help);
6355                         return;
6356                 }
6357         }
6358
6359         snprintf(out, out_size, "Invalid command\n");
6360 }
6361
6362 void
6363 cli_process(char *in, char *out, size_t out_size)
6364 {
6365         char *tokens[CMD_MAX_TOKENS];
6366         uint32_t n_tokens = RTE_DIM(tokens);
6367         int status;
6368
6369         if (is_comment(in))
6370                 return;
6371
6372         status = parse_tokenize_string(in, tokens, &n_tokens);
6373         if (status) {
6374                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
6375                 return;
6376         }
6377
6378         if (n_tokens == 0)
6379                 return;
6380
6381         if (strcmp(tokens[0], "help") == 0) {
6382                 cmd_help(tokens, n_tokens, out, out_size);
6383                 return;
6384         }
6385
6386         if (strcmp(tokens[0], "mempool") == 0) {
6387                 cmd_mempool(tokens, n_tokens, out, out_size);
6388                 return;
6389         }
6390
6391         if (strcmp(tokens[0], "link") == 0) {
6392                 if (strcmp(tokens[1], "show") == 0) {
6393                         cmd_link_show(tokens, n_tokens, out, out_size);
6394                         return;
6395                 }
6396
6397                 cmd_link(tokens, n_tokens, out, out_size);
6398                 return;
6399         }
6400
6401         if (strcmp(tokens[0], "swq") == 0) {
6402                 cmd_swq(tokens, n_tokens, out, out_size);
6403                 return;
6404         }
6405
6406         if (strcmp(tokens[0], "tmgr") == 0) {
6407                 if ((n_tokens >= 3) &&
6408                         (strcmp(tokens[1], "subport") == 0) &&
6409                         (strcmp(tokens[2], "profile") == 0)) {
6410                         cmd_tmgr_subport_profile(tokens, n_tokens,
6411                                 out, out_size);
6412                         return;
6413                 }
6414
6415                 if ((n_tokens >= 3) &&
6416                         (strcmp(tokens[1], "pipe") == 0) &&
6417                         (strcmp(tokens[2], "profile") == 0)) {
6418                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
6419                         return;
6420                 }
6421
6422                 if ((n_tokens >= 5) &&
6423                         (strcmp(tokens[2], "subport") == 0) &&
6424                         (strcmp(tokens[4], "profile") == 0)) {
6425                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
6426                         return;
6427                 }
6428
6429                 if ((n_tokens >= 5) &&
6430                         (strcmp(tokens[2], "subport") == 0) &&
6431                         (strcmp(tokens[4], "pipe") == 0)) {
6432                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
6433                         return;
6434                 }
6435
6436                 cmd_tmgr(tokens, n_tokens, out, out_size);
6437                 return;
6438         }
6439
6440         if (strcmp(tokens[0], "tap") == 0) {
6441                 cmd_tap(tokens, n_tokens, out, out_size);
6442                 return;
6443         }
6444
6445         if (strcmp(tokens[0], "kni") == 0) {
6446                 cmd_kni(tokens, n_tokens, out, out_size);
6447                 return;
6448         }
6449
6450         if (strcmp(tokens[0], "cryptodev") == 0) {
6451                 cmd_cryptodev(tokens, n_tokens, out, out_size);
6452                 return;
6453         }
6454
6455         if (strcmp(tokens[0], "port") == 0) {
6456                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
6457                 return;
6458         }
6459
6460         if (strcmp(tokens[0], "table") == 0) {
6461                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
6462                 return;
6463         }
6464
6465         if (strcmp(tokens[0], "pipeline") == 0) {
6466                 if ((n_tokens >= 3) &&
6467                         (strcmp(tokens[2], "period") == 0)) {
6468                         cmd_pipeline(tokens, n_tokens, out, out_size);
6469                         return;
6470                 }
6471
6472                 if ((n_tokens >= 5) &&
6473                         (strcmp(tokens[2], "port") == 0) &&
6474                         (strcmp(tokens[3], "in") == 0) &&
6475                         (strcmp(tokens[4], "bsz") == 0)) {
6476                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
6477                         return;
6478                 }
6479
6480                 if ((n_tokens >= 5) &&
6481                         (strcmp(tokens[2], "port") == 0) &&
6482                         (strcmp(tokens[3], "out") == 0) &&
6483                         (strcmp(tokens[4], "bsz") == 0)) {
6484                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
6485                         return;
6486                 }
6487
6488                 if ((n_tokens >= 4) &&
6489                         (strcmp(tokens[2], "table") == 0) &&
6490                         (strcmp(tokens[3], "match") == 0)) {
6491                         cmd_pipeline_table(tokens, n_tokens, out, out_size);
6492                         return;
6493                 }
6494
6495                 if ((n_tokens >= 6) &&
6496                         (strcmp(tokens[2], "port") == 0) &&
6497                         (strcmp(tokens[3], "in") == 0) &&
6498                         (strcmp(tokens[5], "table") == 0)) {
6499                         cmd_pipeline_port_in_table(tokens, n_tokens,
6500                                 out, out_size);
6501                         return;
6502                 }
6503
6504                 if ((n_tokens >= 6) &&
6505                         (strcmp(tokens[2], "port") == 0) &&
6506                         (strcmp(tokens[3], "in") == 0) &&
6507                         (strcmp(tokens[5], "stats") == 0)) {
6508                         cmd_pipeline_port_in_stats(tokens, n_tokens,
6509                                 out, out_size);
6510                         return;
6511                 }
6512
6513                 if ((n_tokens >= 6) &&
6514                         (strcmp(tokens[2], "port") == 0) &&
6515                         (strcmp(tokens[3], "in") == 0) &&
6516                         (strcmp(tokens[5], "enable") == 0)) {
6517                         cmd_pipeline_port_in_enable(tokens, n_tokens,
6518                                 out, out_size);
6519                         return;
6520                 }
6521
6522                 if ((n_tokens >= 6) &&
6523                         (strcmp(tokens[2], "port") == 0) &&
6524                         (strcmp(tokens[3], "in") == 0) &&
6525                         (strcmp(tokens[5], "disable") == 0)) {
6526                         cmd_pipeline_port_in_disable(tokens, n_tokens,
6527                                 out, out_size);
6528                         return;
6529                 }
6530
6531                 if ((n_tokens >= 6) &&
6532                         (strcmp(tokens[2], "port") == 0) &&
6533                         (strcmp(tokens[3], "out") == 0) &&
6534                         (strcmp(tokens[5], "stats") == 0)) {
6535                         cmd_pipeline_port_out_stats(tokens, n_tokens,
6536                                 out, out_size);
6537                         return;
6538                 }
6539
6540                 if ((n_tokens >= 5) &&
6541                         (strcmp(tokens[2], "table") == 0) &&
6542                         (strcmp(tokens[4], "stats") == 0)) {
6543                         cmd_pipeline_table_stats(tokens, n_tokens,
6544                                 out, out_size);
6545                         return;
6546                 }
6547
6548                 if ((n_tokens >= 7) &&
6549                         (strcmp(tokens[2], "table") == 0) &&
6550                         (strcmp(tokens[4], "rule") == 0) &&
6551                         (strcmp(tokens[5], "add") == 0) &&
6552                         (strcmp(tokens[6], "match") == 0)) {
6553                         if ((n_tokens >= 8) &&
6554                                 (strcmp(tokens[7], "default") == 0)) {
6555                                 cmd_pipeline_table_rule_add_default(tokens,
6556                                         n_tokens, out, out_size);
6557                                 return;
6558                         }
6559
6560                         cmd_pipeline_table_rule_add(tokens, n_tokens,
6561                                 out, out_size);
6562                         return;
6563                 }
6564
6565                 if ((n_tokens >= 7) &&
6566                         (strcmp(tokens[2], "table") == 0) &&
6567                         (strcmp(tokens[4], "rule") == 0) &&
6568                         (strcmp(tokens[5], "add") == 0) &&
6569                         (strcmp(tokens[6], "bulk") == 0)) {
6570                         cmd_pipeline_table_rule_add_bulk(tokens,
6571                                 n_tokens, out, out_size);
6572                         return;
6573                 }
6574
6575                 if ((n_tokens >= 7) &&
6576                         (strcmp(tokens[2], "table") == 0) &&
6577                         (strcmp(tokens[4], "rule") == 0) &&
6578                         (strcmp(tokens[5], "delete") == 0) &&
6579                         (strcmp(tokens[6], "match") == 0)) {
6580                         if ((n_tokens >= 8) &&
6581                                 (strcmp(tokens[7], "default") == 0)) {
6582                                 cmd_pipeline_table_rule_delete_default(tokens,
6583                                         n_tokens, out, out_size);
6584                                 return;
6585                                 }
6586
6587                         cmd_pipeline_table_rule_delete(tokens, n_tokens,
6588                                 out, out_size);
6589                         return;
6590                 }
6591
6592                 if ((n_tokens >= 6) &&
6593                         (strcmp(tokens[2], "table") == 0) &&
6594                         (strcmp(tokens[4], "rule") == 0) &&
6595                         (strcmp(tokens[5], "show") == 0)) {
6596                         cmd_pipeline_table_rule_show(tokens, n_tokens,
6597                                 out, out_size);
6598                         return;
6599                 }
6600
6601                 if ((n_tokens >= 7) &&
6602                         (strcmp(tokens[2], "table") == 0) &&
6603                         (strcmp(tokens[4], "rule") == 0) &&
6604                         (strcmp(tokens[5], "read") == 0) &&
6605                         (strcmp(tokens[6], "stats") == 0)) {
6606                         cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
6607                                 out, out_size);
6608                         return;
6609                 }
6610
6611                 if ((n_tokens >= 8) &&
6612                         (strcmp(tokens[2], "table") == 0) &&
6613                         (strcmp(tokens[4], "meter") == 0) &&
6614                         (strcmp(tokens[5], "profile") == 0) &&
6615                         (strcmp(tokens[7], "add") == 0)) {
6616                         cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
6617                                 out, out_size);
6618                         return;
6619                 }
6620
6621                 if ((n_tokens >= 8) &&
6622                         (strcmp(tokens[2], "table") == 0) &&
6623                         (strcmp(tokens[4], "meter") == 0) &&
6624                         (strcmp(tokens[5], "profile") == 0) &&
6625                         (strcmp(tokens[7], "delete") == 0)) {
6626                         cmd_pipeline_table_meter_profile_delete(tokens,
6627                                 n_tokens, out, out_size);
6628                         return;
6629                 }
6630
6631                 if ((n_tokens >= 7) &&
6632                         (strcmp(tokens[2], "table") == 0) &&
6633                         (strcmp(tokens[4], "rule") == 0) &&
6634                         (strcmp(tokens[5], "read") == 0) &&
6635                         (strcmp(tokens[6], "meter") == 0)) {
6636                         cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
6637                                 out, out_size);
6638                         return;
6639                 }
6640
6641                 if ((n_tokens >= 5) &&
6642                         (strcmp(tokens[2], "table") == 0) &&
6643                         (strcmp(tokens[4], "dscp") == 0)) {
6644                         cmd_pipeline_table_dscp(tokens, n_tokens,
6645                                 out, out_size);
6646                         return;
6647                 }
6648
6649                 if ((n_tokens >= 7) &&
6650                         (strcmp(tokens[2], "table") == 0) &&
6651                         (strcmp(tokens[4], "rule") == 0) &&
6652                         (strcmp(tokens[5], "read") == 0) &&
6653                         (strcmp(tokens[6], "ttl") == 0)) {
6654                         cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
6655                                 out, out_size);
6656                         return;
6657                 }
6658
6659                 if ((n_tokens >= 7) &&
6660                         (strcmp(tokens[2], "table") == 0) &&
6661                         (strcmp(tokens[4], "rule") == 0) &&
6662                         (strcmp(tokens[5], "read") == 0) &&
6663                         (strcmp(tokens[6], "time") == 0)) {
6664                         cmd_pipeline_table_rule_time_read(tokens, n_tokens,
6665                                 out, out_size);
6666                         return;
6667                 }
6668         }
6669
6670         if (strcmp(tokens[0], "thread") == 0) {
6671                 if ((n_tokens >= 5) &&
6672                         (strcmp(tokens[4], "enable") == 0)) {
6673                         cmd_thread_pipeline_enable(tokens, n_tokens,
6674                                 out, out_size);
6675                         return;
6676                 }
6677
6678                 if ((n_tokens >= 5) &&
6679                         (strcmp(tokens[4], "disable") == 0)) {
6680                         cmd_thread_pipeline_disable(tokens, n_tokens,
6681                                 out, out_size);
6682                         return;
6683                 }
6684         }
6685
6686         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
6687 }
6688
6689 int
6690 cli_script_process(const char *file_name,
6691         size_t msg_in_len_max,
6692         size_t msg_out_len_max)
6693 {
6694         char *msg_in = NULL, *msg_out = NULL;
6695         FILE *f = NULL;
6696
6697         /* Check input arguments */
6698         if ((file_name == NULL) ||
6699                 (strlen(file_name) == 0) ||
6700                 (msg_in_len_max == 0) ||
6701                 (msg_out_len_max == 0))
6702                 return -EINVAL;
6703
6704         msg_in = malloc(msg_in_len_max + 1);
6705         msg_out = malloc(msg_out_len_max + 1);
6706         if ((msg_in == NULL) ||
6707                 (msg_out == NULL)) {
6708                 free(msg_out);
6709                 free(msg_in);
6710                 return -ENOMEM;
6711         }
6712
6713         /* Open input file */
6714         f = fopen(file_name, "r");
6715         if (f == NULL) {
6716                 free(msg_out);
6717                 free(msg_in);
6718                 return -EIO;
6719         }
6720
6721         /* Read file */
6722         for ( ; ; ) {
6723                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
6724                         break;
6725
6726                 printf("%s", msg_in);
6727                 msg_out[0] = 0;
6728
6729                 cli_process(msg_in,
6730                         msg_out,
6731                         msg_out_len_max);
6732
6733                 if (strlen(msg_out))
6734                         printf("%s", msg_out);
6735         }
6736
6737         /* Close file */
6738         fclose(f);
6739         free(msg_out);
6740         free(msg_in);
6741         return 0;
6742 }
6743
6744 static int
6745 cli_rule_file_process(const char *file_name,
6746         size_t line_len_max,
6747         struct table_rule_list **rule_list,
6748         uint32_t *n_rules,
6749         uint32_t *line_number,
6750         char *out,
6751         size_t out_size)
6752 {
6753         struct table_rule_list *list = NULL;
6754         char *line = NULL;
6755         FILE *f = NULL;
6756         uint32_t rule_id = 0, line_id = 0;
6757         int status = 0;
6758
6759         /* Check input arguments */
6760         if ((file_name == NULL) ||
6761                 (strlen(file_name) == 0) ||
6762                 (line_len_max == 0) ||
6763                 (rule_list == NULL) ||
6764                 (n_rules == NULL) ||
6765                 (line_number == NULL) ||
6766                 (out == NULL)) {
6767                 status = -EINVAL;
6768                 goto cli_rule_file_process_free;
6769         }
6770
6771         /* Memory allocation */
6772         list = malloc(sizeof(struct table_rule_list));
6773         if (list == NULL) {
6774                 status = -ENOMEM;
6775                 goto cli_rule_file_process_free;
6776         }
6777
6778         TAILQ_INIT(list);
6779
6780         line = malloc(line_len_max + 1);
6781         if (line == NULL) {
6782                 status = -ENOMEM;
6783                 goto cli_rule_file_process_free;
6784         }
6785
6786         /* Open file */
6787         f = fopen(file_name, "r");
6788         if (f == NULL) {
6789                 status = -EIO;
6790                 goto cli_rule_file_process_free;
6791         }
6792
6793         /* Read file */
6794         for (line_id = 1, rule_id = 0; ; line_id++) {
6795                 char *tokens[CMD_MAX_TOKENS];
6796                 struct table_rule *rule = NULL;
6797                 uint32_t n_tokens, n_tokens_parsed, t0;
6798
6799                 /* Read next line from file. */
6800                 if (fgets(line, line_len_max + 1, f) == NULL)
6801                         break;
6802
6803                 /* Comment. */
6804                 if (is_comment(line))
6805                         continue;
6806
6807                 /* Parse line. */
6808                 n_tokens = RTE_DIM(tokens);
6809                 status = parse_tokenize_string(line, tokens, &n_tokens);
6810                 if (status) {
6811                         status = -EINVAL;
6812                         goto cli_rule_file_process_free;
6813                 }
6814
6815                 /* Empty line. */
6816                 if (n_tokens == 0)
6817                         continue;
6818                 t0 = 0;
6819
6820                 /* Rule alloc and insert. */
6821                 rule = calloc(1, sizeof(struct table_rule));
6822                 if (rule == NULL) {
6823                         status = -ENOMEM;
6824                         goto cli_rule_file_process_free;
6825                 }
6826
6827                 TAILQ_INSERT_TAIL(list, rule, node);
6828
6829                 /* Rule match. */
6830                 n_tokens_parsed = parse_match(tokens + t0,
6831                         n_tokens - t0,
6832                         out,
6833                         out_size,
6834                         &rule->match);
6835                 if (n_tokens_parsed == 0) {
6836                         status = -EINVAL;
6837                         goto cli_rule_file_process_free;
6838                 }
6839                 t0 += n_tokens_parsed;
6840
6841                 /* Rule action. */
6842                 n_tokens_parsed = parse_table_action(tokens + t0,
6843                         n_tokens - t0,
6844                         out,
6845                         out_size,
6846                         &rule->action);
6847                 if (n_tokens_parsed == 0) {
6848                         status = -EINVAL;
6849                         goto cli_rule_file_process_free;
6850                 }
6851                 t0 += n_tokens_parsed;
6852
6853                 /* Line completed. */
6854                 if (t0 < n_tokens) {
6855                         status = -EINVAL;
6856                         goto cli_rule_file_process_free;
6857                 }
6858
6859                 /* Increment rule count */
6860                 rule_id++;
6861         }
6862
6863         /* Close file */
6864         fclose(f);
6865
6866         /* Memory free */
6867         free(line);
6868
6869         *rule_list = list;
6870         *n_rules = rule_id;
6871         *line_number = line_id;
6872         return 0;
6873
6874 cli_rule_file_process_free:
6875         if (rule_list != NULL)
6876                 *rule_list = NULL;
6877
6878         if (n_rules != NULL)
6879                 *n_rules = rule_id;
6880
6881         if (line_number != NULL)
6882                 *line_number = line_id;
6883
6884         if (list != NULL)
6885                 for ( ; ; ) {
6886                         struct table_rule *rule;
6887
6888                         rule = TAILQ_FIRST(list);
6889                         if (rule == NULL)
6890                                 break;
6891
6892                         TAILQ_REMOVE(list, rule, node);
6893                         free(rule);
6894                 }
6895
6896         if (f)
6897                 fclose(f);
6898         free(line);
6899         free(list);
6900
6901         return status;
6902 }