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