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