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