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