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