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