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