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