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