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