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