3ff7caaca50e5c4292dd67889e0646c34d58786e
[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
1037 static void
1038 cmd_table_action_profile(char **tokens,
1039         uint32_t n_tokens,
1040         char *out,
1041         size_t out_size)
1042 {
1043         struct table_action_profile_params p;
1044         struct table_action_profile *ap;
1045         char *name;
1046         uint32_t t0;
1047
1048         memset(&p, 0, sizeof(p));
1049
1050         if (n_tokens < 8) {
1051                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1052                 return;
1053         }
1054
1055         if (strcmp(tokens[1], "action") != 0) {
1056                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
1057                 return;
1058         }
1059
1060         if (strcmp(tokens[2], "profile") != 0) {
1061                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1062                 return;
1063         }
1064
1065         name = tokens[3];
1066
1067         if (strcmp(tokens[4], "ipv4") == 0)
1068                 p.common.ip_version = 1;
1069         else if (strcmp(tokens[4], "ipv6") == 0)
1070                 p.common.ip_version = 0;
1071         else {
1072                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
1073                 return;
1074         }
1075
1076         if (strcmp(tokens[5], "offset") != 0) {
1077                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1078                 return;
1079         }
1080
1081         if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
1082                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
1083                 return;
1084         }
1085
1086         if (strcmp(tokens[7], "fwd") != 0) {
1087                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
1088                 return;
1089         }
1090
1091         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
1092
1093         t0 = 8;
1094         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
1095                 if (n_tokens < t0 + 7) {
1096                         snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
1097                         return;
1098                 }
1099
1100                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1101                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1102                         return;
1103                 }
1104
1105                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
1106                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1107                         return;
1108                 }
1109
1110                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
1111                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1112                         return;
1113                 }
1114
1115                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
1116                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
1117                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1118                         return;
1119                 }
1120
1121                 if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
1122                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
1123                         return;
1124                 }
1125
1126                 if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) {
1127                         snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
1128                         return;
1129                 }
1130
1131                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
1132                 t0 += 7;
1133         } /* balance */
1134
1135         if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
1136                 if (n_tokens < t0 + 6) {
1137                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1138                                 "table action profile meter");
1139                         return;
1140                 }
1141
1142                 if (strcmp(tokens[t0 + 1], "srtcm") == 0)
1143                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
1144                 else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
1145                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
1146                 else {
1147                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1148                                 "srtcm or trtcm");
1149                         return;
1150                 }
1151
1152                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
1153                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
1154                         return;
1155                 }
1156
1157                 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
1158                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
1159                         return;
1160                 }
1161
1162                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
1163                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1164                         return;
1165                 }
1166
1167                 if (strcmp(tokens[t0 + 5], "none") == 0) {
1168                         p.mtr.n_packets_enabled = 0;
1169                         p.mtr.n_bytes_enabled = 0;
1170                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
1171                         p.mtr.n_packets_enabled = 1;
1172                         p.mtr.n_bytes_enabled = 0;
1173                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
1174                         p.mtr.n_packets_enabled = 0;
1175                         p.mtr.n_bytes_enabled = 1;
1176                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
1177                         p.mtr.n_packets_enabled = 1;
1178                         p.mtr.n_bytes_enabled = 1;
1179                 } else {
1180                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1181                                 "none or pkts or bytes or both");
1182                         return;
1183                 }
1184
1185                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
1186                 t0 += 6;
1187         } /* meter */
1188
1189         if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
1190                 if (n_tokens < t0 + 5) {
1191                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1192                                 "table action profile tm");
1193                         return;
1194                 }
1195
1196                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
1197                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
1198                         return;
1199                 }
1200
1201                 if (parser_read_uint32(&p.tm.n_subports_per_port,
1202                         tokens[t0 + 2]) != 0) {
1203                         snprintf(out, out_size, MSG_ARG_INVALID,
1204                                 "n_subports_per_port");
1205                         return;
1206                 }
1207
1208                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
1209                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1210                         return;
1211                 }
1212
1213                 if (parser_read_uint32(&p.tm.n_pipes_per_subport,
1214                         tokens[t0 + 4]) != 0) {
1215                         snprintf(out, out_size, MSG_ARG_INVALID,
1216                                 "n_pipes_per_subport");
1217                         return;
1218                 }
1219
1220                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1221                 t0 += 5;
1222         } /* tm */
1223
1224         if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
1225                 uint32_t n_extra_tokens = 0;
1226
1227                 if (n_tokens < t0 + 2) {
1228                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1229                                 "action profile encap");
1230                         return;
1231                 }
1232
1233                 if (strcmp(tokens[t0 + 1], "ether") == 0)
1234                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1235                 else if (strcmp(tokens[t0 + 1], "vlan") == 0)
1236                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1237                 else if (strcmp(tokens[t0 + 1], "qinq") == 0)
1238                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1239                 else if (strcmp(tokens[t0 + 1], "mpls") == 0)
1240                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1241                 else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
1242                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1243                 else if (strcmp(tokens[t0 + 1], "vxlan") == 0) {
1244                         if (n_tokens < t0 + 2 + 5) {
1245                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1246                                         "action profile encap vxlan");
1247                                 return;
1248                         }
1249
1250                         if (strcmp(tokens[t0 + 2], "offset") != 0) {
1251                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1252                                         "vxlan: offset");
1253                                 return;
1254                         }
1255
1256                         if (parser_read_uint32(&p.encap.vxlan.data_offset,
1257                                 tokens[t0 + 2 + 1]) != 0) {
1258                                 snprintf(out, out_size, MSG_ARG_INVALID,
1259                                         "vxlan: ether_offset");
1260                                 return;
1261                         }
1262
1263                         if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0)
1264                                 p.encap.vxlan.ip_version = 1;
1265                         else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0)
1266                                 p.encap.vxlan.ip_version = 0;
1267                         else {
1268                                 snprintf(out, out_size, MSG_ARG_INVALID,
1269                                         "vxlan: ipv4 or ipv6");
1270                                 return;
1271                         }
1272
1273                         if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) {
1274                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1275                                         "vxlan: vlan");
1276                                 return;
1277                         }
1278
1279                         if (strcmp(tokens[t0 + 2 + 4], "on") == 0)
1280                                 p.encap.vxlan.vlan = 1;
1281                         else if (strcmp(tokens[t0 + 2 + 4], "off") == 0)
1282                                 p.encap.vxlan.vlan = 0;
1283                         else {
1284                                 snprintf(out, out_size, MSG_ARG_INVALID,
1285                                         "vxlan: on or off");
1286                                 return;
1287                         }
1288
1289                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN;
1290                         n_extra_tokens = 5;
1291                 } else {
1292                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1293                         return;
1294                 }
1295
1296                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1297                 t0 += 2 + n_extra_tokens;
1298         } /* encap */
1299
1300         if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
1301                 if (n_tokens < t0 + 4) {
1302                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1303                                 "table action profile nat");
1304                         return;
1305                 }
1306
1307                 if (strcmp(tokens[t0 + 1], "src") == 0)
1308                         p.nat.source_nat = 1;
1309                 else if (strcmp(tokens[t0 + 1], "dst") == 0)
1310                         p.nat.source_nat = 0;
1311                 else {
1312                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1313                                 "src or dst");
1314                         return;
1315                 }
1316
1317                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
1318                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1319                         return;
1320                 }
1321
1322                 if (strcmp(tokens[t0 + 3], "tcp") == 0)
1323                         p.nat.proto = 0x06;
1324                 else if (strcmp(tokens[t0 + 3], "udp") == 0)
1325                         p.nat.proto = 0x11;
1326                 else {
1327                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1328                                 "tcp or udp");
1329                         return;
1330                 }
1331
1332                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1333                 t0 += 4;
1334         } /* nat */
1335
1336         if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
1337                 if (n_tokens < t0 + 4) {
1338                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1339                                 "table action profile ttl");
1340                         return;
1341                 }
1342
1343                 if (strcmp(tokens[t0 + 1], "drop") == 0)
1344                         p.ttl.drop = 1;
1345                 else if (strcmp(tokens[t0 + 1], "fwd") == 0)
1346                         p.ttl.drop = 0;
1347                 else {
1348                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1349                                 "drop or fwd");
1350                         return;
1351                 }
1352
1353                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
1354                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1355                         return;
1356                 }
1357
1358                 if (strcmp(tokens[t0 + 3], "none") == 0)
1359                         p.ttl.n_packets_enabled = 0;
1360                 else if (strcmp(tokens[t0 + 3], "pkts") == 0)
1361                         p.ttl.n_packets_enabled = 1;
1362                 else {
1363                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1364                                 "none or pkts");
1365                         return;
1366                 }
1367
1368                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1369                 t0 += 4;
1370         } /* ttl */
1371
1372         if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
1373                 if (n_tokens < t0 + 2) {
1374                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1375                                 "table action profile stats");
1376                         return;
1377                 }
1378
1379                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1380                         p.stats.n_packets_enabled = 1;
1381                         p.stats.n_bytes_enabled = 0;
1382                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1383                         p.stats.n_packets_enabled = 0;
1384                         p.stats.n_bytes_enabled = 1;
1385                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
1386                         p.stats.n_packets_enabled = 1;
1387                         p.stats.n_bytes_enabled = 1;
1388                 } else {
1389                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1390                                 "pkts or bytes or both");
1391                         return;
1392                 }
1393
1394                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1395                 t0 += 2;
1396         } /* stats */
1397
1398         if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
1399                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1400                 t0 += 1;
1401         } /* time */
1402
1403         if ((t0 < n_tokens) && (strcmp(tokens[t0], "sym_crypto") == 0)) {
1404                 struct cryptodev *cryptodev;
1405                 struct mempool *mempool;
1406
1407                 if (n_tokens < t0 + 9 ||
1408                                 strcmp(tokens[t0 + 1], "dev") ||
1409                                 strcmp(tokens[t0 + 3], "offset") ||
1410                                 strcmp(tokens[t0 + 5], "mempool_create") ||
1411                                 strcmp(tokens[t0 + 7], "mempool_init")) {
1412                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1413                                 "table action profile sym_crypto");
1414                         return;
1415                 }
1416
1417                 cryptodev = cryptodev_find(tokens[t0 + 2]);
1418                 if (cryptodev == NULL) {
1419                         snprintf(out, out_size, MSG_ARG_INVALID,
1420                                 "table action profile sym_crypto");
1421                         return;
1422                 }
1423
1424                 p.sym_crypto.cryptodev_id = cryptodev->dev_id;
1425
1426                 if (parser_read_uint32(&p.sym_crypto.op_offset,
1427                                 tokens[t0 + 4]) != 0) {
1428                         snprintf(out, out_size, MSG_ARG_INVALID,
1429                                         "table action profile sym_crypto");
1430                         return;
1431                 }
1432
1433                 mempool = mempool_find(tokens[t0 + 6]);
1434                 if (mempool == NULL) {
1435                         snprintf(out, out_size, MSG_ARG_INVALID,
1436                                 "table action profile sym_crypto");
1437                         return;
1438                 }
1439                 p.sym_crypto.mp_create = mempool->m;
1440
1441                 mempool = mempool_find(tokens[t0 + 8]);
1442                 if (mempool == NULL) {
1443                         snprintf(out, out_size, MSG_ARG_INVALID,
1444                                 "table action profile sym_crypto");
1445                         return;
1446                 }
1447                 p.sym_crypto.mp_init = mempool->m;
1448
1449                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_SYM_CRYPTO;
1450
1451                 t0 += 9;
1452         } /* sym_crypto */
1453
1454         if (t0 < n_tokens) {
1455                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1456                 return;
1457         }
1458
1459         ap = table_action_profile_create(name, &p);
1460         if (ap == NULL) {
1461                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1462                 return;
1463         }
1464 }
1465
1466 static const char cmd_pipeline_help[] =
1467 "pipeline <pipeline_name>\n"
1468 "   period <timer_period_ms>\n"
1469 "   offset_port_id <offset_port_id>\n"
1470 "   cpu <cpu_id>\n";
1471
1472 static void
1473 cmd_pipeline(char **tokens,
1474         uint32_t n_tokens,
1475         char *out,
1476         size_t out_size)
1477 {
1478         struct pipeline_params p;
1479         char *name;
1480         struct pipeline *pipeline;
1481
1482         if (n_tokens != 8) {
1483                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1484                 return;
1485         }
1486
1487         name = tokens[1];
1488
1489         if (strcmp(tokens[2], "period") != 0) {
1490                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
1491                 return;
1492         }
1493
1494         if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
1495                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
1496                 return;
1497         }
1498
1499         if (strcmp(tokens[4], "offset_port_id") != 0) {
1500                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
1501                 return;
1502         }
1503
1504         if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
1505                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
1506                 return;
1507         }
1508
1509         if (strcmp(tokens[6], "cpu") != 0) {
1510                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
1511                 return;
1512         }
1513
1514         if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
1515                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
1516                 return;
1517         }
1518
1519         pipeline = pipeline_create(name, &p);
1520         if (pipeline == NULL) {
1521                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1522                 return;
1523         }
1524 }
1525
1526 static const char cmd_pipeline_port_in_help[] =
1527 "pipeline <pipeline_name> port in\n"
1528 "   bsz <burst_size>\n"
1529 "   link <link_name> rxq <queue_id>\n"
1530 "   | swq <swq_name>\n"
1531 "   | tmgr <tmgr_name>\n"
1532 "   | tap <tap_name> mempool <mempool_name> mtu <mtu>\n"
1533 "   | kni <kni_name>\n"
1534 "   | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>\n"
1535 "   | cryptodev <cryptodev_name> rxq <queue_id>\n"
1536 "   [action <port_in_action_profile_name>]\n"
1537 "   [disabled]\n";
1538
1539 static void
1540 cmd_pipeline_port_in(char **tokens,
1541         uint32_t n_tokens,
1542         char *out,
1543         size_t out_size)
1544 {
1545         struct port_in_params p;
1546         char *pipeline_name;
1547         uint32_t t0;
1548         int enabled, status;
1549
1550         if (n_tokens < 7) {
1551                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1552                 return;
1553         }
1554
1555         pipeline_name = tokens[1];
1556
1557         if (strcmp(tokens[2], "port") != 0) {
1558                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1559                 return;
1560         }
1561
1562         if (strcmp(tokens[3], "in") != 0) {
1563                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1564                 return;
1565         }
1566
1567         if (strcmp(tokens[4], "bsz") != 0) {
1568                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1569                 return;
1570         }
1571
1572         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1573                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1574                 return;
1575         }
1576
1577         t0 = 6;
1578
1579         if (strcmp(tokens[t0], "link") == 0) {
1580                 if (n_tokens < t0 + 4) {
1581                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1582                                 "pipeline port in link");
1583                         return;
1584                 }
1585
1586                 p.type = PORT_IN_RXQ;
1587
1588                 p.dev_name = tokens[t0 + 1];
1589
1590                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
1591                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
1592                         return;
1593                 }
1594
1595                 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1596                         snprintf(out, out_size, MSG_ARG_INVALID,
1597                                 "queue_id");
1598                         return;
1599                 }
1600                 t0 += 4;
1601         } else if (strcmp(tokens[t0], "swq") == 0) {
1602                 if (n_tokens < t0 + 2) {
1603                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1604                                 "pipeline port in swq");
1605                         return;
1606                 }
1607
1608                 p.type = PORT_IN_SWQ;
1609
1610                 p.dev_name = tokens[t0 + 1];
1611
1612                 t0 += 2;
1613         } else if (strcmp(tokens[t0], "tmgr") == 0) {
1614                 if (n_tokens < t0 + 2) {
1615                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1616                                 "pipeline port in tmgr");
1617                         return;
1618                 }
1619
1620                 p.type = PORT_IN_TMGR;
1621
1622                 p.dev_name = tokens[t0 + 1];
1623
1624                 t0 += 2;
1625         } else if (strcmp(tokens[t0], "tap") == 0) {
1626                 if (n_tokens < t0 + 6) {
1627                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1628                                 "pipeline port in tap");
1629                         return;
1630                 }
1631
1632                 p.type = PORT_IN_TAP;
1633
1634                 p.dev_name = tokens[t0 + 1];
1635
1636                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
1637                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1638                                 "mempool");
1639                         return;
1640                 }
1641
1642                 p.tap.mempool_name = tokens[t0 + 3];
1643
1644                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
1645                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1646                                 "mtu");
1647                         return;
1648                 }
1649
1650                 if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
1651                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
1652                         return;
1653                 }
1654
1655                 t0 += 6;
1656         } else if (strcmp(tokens[t0], "kni") == 0) {
1657                 if (n_tokens < t0 + 2) {
1658                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1659                                 "pipeline port in kni");
1660                         return;
1661                 }
1662
1663                 p.type = PORT_IN_KNI;
1664
1665                 p.dev_name = tokens[t0 + 1];
1666
1667                 t0 += 2;
1668         } else if (strcmp(tokens[t0], "source") == 0) {
1669                 if (n_tokens < t0 + 6) {
1670                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1671                                 "pipeline port in source");
1672                         return;
1673                 }
1674
1675                 p.type = PORT_IN_SOURCE;
1676
1677                 p.dev_name = NULL;
1678
1679                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
1680                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1681                                 "mempool");
1682                         return;
1683                 }
1684
1685                 p.source.mempool_name = tokens[t0 + 2];
1686
1687                 if (strcmp(tokens[t0 + 3], "file") != 0) {
1688                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1689                                 "file");
1690                         return;
1691                 }
1692
1693                 p.source.file_name = tokens[t0 + 4];
1694
1695                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
1696                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1697                                 "bpp");
1698                         return;
1699                 }
1700
1701                 if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) {
1702                         snprintf(out, out_size, MSG_ARG_INVALID,
1703                                 "n_bytes_per_pkt");
1704                         return;
1705                 }
1706
1707                 t0 += 7;
1708         } else if (strcmp(tokens[t0], "cryptodev") == 0) {
1709                 if (n_tokens < t0 + 3) {
1710                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1711                                 "pipeline port in cryptodev");
1712                         return;
1713                 }
1714
1715                 p.type = PORT_IN_CRYPTODEV;
1716
1717                 p.dev_name = tokens[t0 + 1];
1718                 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1719                         snprintf(out, out_size, MSG_ARG_INVALID,
1720                                 "rxq");
1721                         return;
1722                 }
1723
1724                 p.cryptodev.arg_callback = NULL;
1725                 p.cryptodev.f_callback = NULL;
1726
1727                 t0 += 4;
1728         } else {
1729                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1730                 return;
1731         }
1732
1733         p.action_profile_name = NULL;
1734         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1735                 if (n_tokens < t0 + 2) {
1736                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1737                         return;
1738                 }
1739
1740                 p.action_profile_name = tokens[t0 + 1];
1741
1742                 t0 += 2;
1743         }
1744
1745         enabled = 1;
1746         if ((n_tokens > t0) &&
1747                 (strcmp(tokens[t0], "disabled") == 0)) {
1748                 enabled = 0;
1749
1750                 t0 += 1;
1751         }
1752
1753         if (n_tokens != t0) {
1754                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1755                 return;
1756         }
1757
1758         status = pipeline_port_in_create(pipeline_name,
1759                 &p, enabled);
1760         if (status) {
1761                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1762                 return;
1763         }
1764 }
1765
1766 static const char cmd_pipeline_port_out_help[] =
1767 "pipeline <pipeline_name> port out\n"
1768 "   bsz <burst_size>\n"
1769 "   link <link_name> txq <txq_id>\n"
1770 "   | swq <swq_name>\n"
1771 "   | tmgr <tmgr_name>\n"
1772 "   | tap <tap_name>\n"
1773 "   | kni <kni_name>\n"
1774 "   | sink [file <file_name> pkts <max_n_pkts>]\n"
1775 "   | cryptodev <cryptodev_name> txq <txq_id> offset <crypto_op_offset>\n";
1776
1777 static void
1778 cmd_pipeline_port_out(char **tokens,
1779         uint32_t n_tokens,
1780         char *out,
1781         size_t out_size)
1782 {
1783         struct port_out_params p;
1784         char *pipeline_name;
1785         int status;
1786
1787         memset(&p, 0, sizeof(p));
1788
1789         if (n_tokens < 7) {
1790                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1791                 return;
1792         }
1793
1794         pipeline_name = tokens[1];
1795
1796         if (strcmp(tokens[2], "port") != 0) {
1797                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1798                 return;
1799         }
1800
1801         if (strcmp(tokens[3], "out") != 0) {
1802                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1803                 return;
1804         }
1805
1806         if (strcmp(tokens[4], "bsz") != 0) {
1807                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1808                 return;
1809         }
1810
1811         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1812                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1813                 return;
1814         }
1815
1816         if (strcmp(tokens[6], "link") == 0) {
1817                 if (n_tokens != 10) {
1818                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1819                                 "pipeline port out link");
1820                         return;
1821                 }
1822
1823                 p.type = PORT_OUT_TXQ;
1824
1825                 p.dev_name = tokens[7];
1826
1827                 if (strcmp(tokens[8], "txq") != 0) {
1828                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1829                         return;
1830                 }
1831
1832                 if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
1833                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1834                         return;
1835                 }
1836         } else if (strcmp(tokens[6], "swq") == 0) {
1837                 if (n_tokens != 8) {
1838                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1839                                 "pipeline port out swq");
1840                         return;
1841                 }
1842
1843                 p.type = PORT_OUT_SWQ;
1844
1845                 p.dev_name = tokens[7];
1846         } else if (strcmp(tokens[6], "tmgr") == 0) {
1847                 if (n_tokens != 8) {
1848                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1849                                 "pipeline port out tmgr");
1850                         return;
1851                 }
1852
1853                 p.type = PORT_OUT_TMGR;
1854
1855                 p.dev_name = tokens[7];
1856         } else if (strcmp(tokens[6], "tap") == 0) {
1857                 if (n_tokens != 8) {
1858                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1859                                 "pipeline port out tap");
1860                         return;
1861                 }
1862
1863                 p.type = PORT_OUT_TAP;
1864
1865                 p.dev_name = tokens[7];
1866         } else if (strcmp(tokens[6], "kni") == 0) {
1867                 if (n_tokens != 8) {
1868                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1869                                 "pipeline port out kni");
1870                         return;
1871                 }
1872
1873                 p.type = PORT_OUT_KNI;
1874
1875                 p.dev_name = tokens[7];
1876         } else if (strcmp(tokens[6], "sink") == 0) {
1877                 if ((n_tokens != 7) && (n_tokens != 11)) {
1878                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1879                                 "pipeline port out sink");
1880                         return;
1881                 }
1882
1883                 p.type = PORT_OUT_SINK;
1884
1885                 p.dev_name = NULL;
1886
1887                 if (n_tokens == 7) {
1888                         p.sink.file_name = NULL;
1889                         p.sink.max_n_pkts = 0;
1890                 } else {
1891                         if (strcmp(tokens[7], "file") != 0) {
1892                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1893                                         "file");
1894                                 return;
1895                         }
1896
1897                         p.sink.file_name = tokens[8];
1898
1899                         if (strcmp(tokens[9], "pkts") != 0) {
1900                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1901                                 return;
1902                         }
1903
1904                         if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) {
1905                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1906                                 return;
1907                         }
1908                 }
1909
1910         } else if (strcmp(tokens[6], "cryptodev") == 0) {
1911                 if (n_tokens != 12) {
1912                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1913                                 "pipeline port out cryptodev");
1914                         return;
1915                 }
1916
1917                 p.type = PORT_OUT_CRYPTODEV;
1918
1919                 p.dev_name = tokens[7];
1920
1921                 if (strcmp(tokens[8], "txq")) {
1922                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1923                                 "pipeline port out cryptodev");
1924                         return;
1925                 }
1926
1927                 if (parser_read_uint16(&p.cryptodev.queue_id, tokens[9])
1928                                 != 0) {
1929                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1930                         return;
1931                 }
1932
1933                 if (strcmp(tokens[10], "offset")) {
1934                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1935                                 "pipeline port out cryptodev");
1936                         return;
1937                 }
1938
1939                 if (parser_read_uint32(&p.cryptodev.op_offset, tokens[11])
1940                                 != 0) {
1941                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1942                         return;
1943                 }
1944         } else {
1945                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1946                 return;
1947         }
1948
1949         status = pipeline_port_out_create(pipeline_name, &p);
1950         if (status) {
1951                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1952                 return;
1953         }
1954 }
1955
1956 static const char cmd_pipeline_table_help[] =
1957 "pipeline <pipeline_name> table\n"
1958 "       match\n"
1959 "       acl\n"
1960 "           ipv4 | ipv6\n"
1961 "           offset <ip_header_offset>\n"
1962 "           size <n_rules>\n"
1963 "       | array\n"
1964 "           offset <key_offset>\n"
1965 "           size <n_keys>\n"
1966 "       | hash\n"
1967 "           ext | lru\n"
1968 "           key <key_size>\n"
1969 "           mask <key_mask>\n"
1970 "           offset <key_offset>\n"
1971 "           buckets <n_buckets>\n"
1972 "           size <n_keys>\n"
1973 "       | lpm\n"
1974 "           ipv4 | ipv6\n"
1975 "           offset <ip_header_offset>\n"
1976 "           size <n_rules>\n"
1977 "       | stub\n"
1978 "   [action <table_action_profile_name>]\n";
1979
1980 static void
1981 cmd_pipeline_table(char **tokens,
1982         uint32_t n_tokens,
1983         char *out,
1984         size_t out_size)
1985 {
1986         uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1987         struct table_params p;
1988         char *pipeline_name;
1989         uint32_t t0;
1990         int status;
1991
1992         if (n_tokens < 5) {
1993                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1994                 return;
1995         }
1996
1997         pipeline_name = tokens[1];
1998
1999         if (strcmp(tokens[2], "table") != 0) {
2000                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2001                 return;
2002         }
2003
2004         if (strcmp(tokens[3], "match") != 0) {
2005                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2006                 return;
2007         }
2008
2009         t0 = 4;
2010         if (strcmp(tokens[t0], "acl") == 0) {
2011                 if (n_tokens < t0 + 6) {
2012                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2013                                 "pipeline table acl");
2014                         return;
2015                 }
2016
2017                 p.match_type = TABLE_ACL;
2018
2019                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
2020                         p.match.acl.ip_version = 1;
2021                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
2022                         p.match.acl.ip_version = 0;
2023                 else {
2024                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2025                                 "ipv4 or ipv6");
2026                         return;
2027                 }
2028
2029                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
2030                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2031                         return;
2032                 }
2033
2034                 if (parser_read_uint32(&p.match.acl.ip_header_offset,
2035                         tokens[t0 + 3]) != 0) {
2036                         snprintf(out, out_size, MSG_ARG_INVALID,
2037                                 "ip_header_offset");
2038                         return;
2039                 }
2040
2041                 if (strcmp(tokens[t0 + 4], "size") != 0) {
2042                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2043                         return;
2044                 }
2045
2046                 if (parser_read_uint32(&p.match.acl.n_rules,
2047                         tokens[t0 + 5]) != 0) {
2048                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2049                         return;
2050                 }
2051
2052                 t0 += 6;
2053         } else if (strcmp(tokens[t0], "array") == 0) {
2054                 if (n_tokens < t0 + 5) {
2055                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2056                                 "pipeline table array");
2057                         return;
2058                 }
2059
2060                 p.match_type = TABLE_ARRAY;
2061
2062                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
2063                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2064                         return;
2065                 }
2066
2067                 if (parser_read_uint32(&p.match.array.key_offset,
2068                         tokens[t0 + 2]) != 0) {
2069                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2070                         return;
2071                 }
2072
2073                 if (strcmp(tokens[t0 + 3], "size") != 0) {
2074                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2075                         return;
2076                 }
2077
2078                 if (parser_read_uint32(&p.match.array.n_keys,
2079                         tokens[t0 + 4]) != 0) {
2080                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
2081                         return;
2082                 }
2083
2084                 t0 += 5;
2085         } else if (strcmp(tokens[t0], "hash") == 0) {
2086                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
2087
2088                 if (n_tokens < t0 + 12) {
2089                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2090                                 "pipeline table hash");
2091                         return;
2092                 }
2093
2094                 p.match_type = TABLE_HASH;
2095
2096                 if (strcmp(tokens[t0 + 1], "ext") == 0)
2097                         p.match.hash.extendable_bucket = 1;
2098                 else if (strcmp(tokens[t0 + 1], "lru") == 0)
2099                         p.match.hash.extendable_bucket = 0;
2100                 else {
2101                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2102                                 "ext or lru");
2103                         return;
2104                 }
2105
2106                 if (strcmp(tokens[t0 + 2], "key") != 0) {
2107                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
2108                         return;
2109                 }
2110
2111                 if ((parser_read_uint32(&p.match.hash.key_size,
2112                         tokens[t0 + 3]) != 0) ||
2113                         (p.match.hash.key_size == 0) ||
2114                         (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
2115                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
2116                         return;
2117                 }
2118
2119                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
2120                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
2121                         return;
2122                 }
2123
2124                 if ((parse_hex_string(tokens[t0 + 5],
2125                         key_mask, &key_mask_size) != 0) ||
2126                         (key_mask_size != p.match.hash.key_size)) {
2127                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
2128                         return;
2129                 }
2130                 p.match.hash.key_mask = key_mask;
2131
2132                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
2133                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2134                         return;
2135                 }
2136
2137                 if (parser_read_uint32(&p.match.hash.key_offset,
2138                         tokens[t0 + 7]) != 0) {
2139                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2140                         return;
2141                 }
2142
2143                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
2144                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
2145                         return;
2146                 }
2147
2148                 if (parser_read_uint32(&p.match.hash.n_buckets,
2149                         tokens[t0 + 9]) != 0) {
2150                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
2151                         return;
2152                 }
2153
2154                 if (strcmp(tokens[t0 + 10], "size") != 0) {
2155                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2156                         return;
2157                 }
2158
2159                 if (parser_read_uint32(&p.match.hash.n_keys,
2160                         tokens[t0 + 11]) != 0) {
2161                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
2162                         return;
2163                 }
2164
2165                 t0 += 12;
2166         } else if (strcmp(tokens[t0], "lpm") == 0) {
2167                 if (n_tokens < t0 + 6) {
2168                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2169                                 "pipeline table lpm");
2170                         return;
2171                 }
2172
2173                 p.match_type = TABLE_LPM;
2174
2175                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
2176                         p.match.lpm.key_size = 4;
2177                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
2178                         p.match.lpm.key_size = 16;
2179                 else {
2180                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2181                                 "ipv4 or ipv6");
2182                         return;
2183                 }
2184
2185                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
2186                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2187                         return;
2188                 }
2189
2190                 if (parser_read_uint32(&p.match.lpm.key_offset,
2191                         tokens[t0 + 3]) != 0) {
2192                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2193                         return;
2194                 }
2195
2196                 if (strcmp(tokens[t0 + 4], "size") != 0) {
2197                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2198                         return;
2199                 }
2200
2201                 if (parser_read_uint32(&p.match.lpm.n_rules,
2202                         tokens[t0 + 5]) != 0) {
2203                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2204                         return;
2205                 }
2206
2207                 t0 += 6;
2208         } else if (strcmp(tokens[t0], "stub") == 0) {
2209                 p.match_type = TABLE_STUB;
2210
2211                 t0 += 1;
2212         } else {
2213                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
2214                 return;
2215         }
2216
2217         p.action_profile_name = NULL;
2218         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
2219                 if (n_tokens < t0 + 2) {
2220                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
2221                         return;
2222                 }
2223
2224                 p.action_profile_name = tokens[t0 + 1];
2225
2226                 t0 += 2;
2227         }
2228
2229         if (n_tokens > t0) {
2230                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2231                 return;
2232         }
2233
2234         status = pipeline_table_create(pipeline_name, &p);
2235         if (status) {
2236                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2237                 return;
2238         }
2239 }
2240
2241 static const char cmd_pipeline_port_in_table_help[] =
2242 "pipeline <pipeline_name> port in <port_id> table <table_id>\n";
2243
2244 static void
2245 cmd_pipeline_port_in_table(char **tokens,
2246         uint32_t n_tokens,
2247         char *out,
2248         size_t out_size)
2249 {
2250         char *pipeline_name;
2251         uint32_t port_id, table_id;
2252         int status;
2253
2254         if (n_tokens != 7) {
2255                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2256                 return;
2257         }
2258
2259         pipeline_name = tokens[1];
2260
2261         if (strcmp(tokens[2], "port") != 0) {
2262                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2263                 return;
2264         }
2265
2266         if (strcmp(tokens[3], "in") != 0) {
2267                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2268                 return;
2269         }
2270
2271         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2272                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2273                 return;
2274         }
2275
2276         if (strcmp(tokens[5], "table") != 0) {
2277                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2278                 return;
2279         }
2280
2281         if (parser_read_uint32(&table_id, tokens[6]) != 0) {
2282                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2283                 return;
2284         }
2285
2286         status = pipeline_port_in_connect_to_table(pipeline_name,
2287                 port_id,
2288                 table_id);
2289         if (status) {
2290                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2291                 return;
2292         }
2293 }
2294
2295
2296 static const char cmd_pipeline_port_in_stats_help[] =
2297 "pipeline <pipeline_name> port in <port_id> stats read [clear]\n";
2298
2299 #define MSG_PIPELINE_PORT_IN_STATS                         \
2300         "Pkts in: %" PRIu64 "\n"                           \
2301         "Pkts dropped by AH: %" PRIu64 "\n"                \
2302         "Pkts dropped by other: %" PRIu64 "\n"
2303
2304 static void
2305 cmd_pipeline_port_in_stats(char **tokens,
2306         uint32_t n_tokens,
2307         char *out,
2308         size_t out_size)
2309 {
2310         struct rte_pipeline_port_in_stats stats;
2311         char *pipeline_name;
2312         uint32_t port_id;
2313         int clear, status;
2314
2315         if ((n_tokens != 7) && (n_tokens != 8)) {
2316                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2317                 return;
2318         }
2319
2320         pipeline_name = tokens[1];
2321
2322         if (strcmp(tokens[2], "port") != 0) {
2323                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2324                 return;
2325         }
2326
2327         if (strcmp(tokens[3], "in") != 0) {
2328                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2329                 return;
2330         }
2331
2332         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2333                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2334                 return;
2335         }
2336
2337         if (strcmp(tokens[5], "stats") != 0) {
2338                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2339                 return;
2340         }
2341
2342         if (strcmp(tokens[6], "read") != 0) {
2343                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2344                 return;
2345         }
2346
2347         clear = 0;
2348         if (n_tokens == 8) {
2349                 if (strcmp(tokens[7], "clear") != 0) {
2350                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2351                         return;
2352                 }
2353
2354                 clear = 1;
2355         }
2356
2357         status = pipeline_port_in_stats_read(pipeline_name,
2358                 port_id,
2359                 &stats,
2360                 clear);
2361         if (status) {
2362                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2363                 return;
2364         }
2365
2366         snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
2367                 stats.stats.n_pkts_in,
2368                 stats.n_pkts_dropped_by_ah,
2369                 stats.stats.n_pkts_drop);
2370 }
2371
2372
2373 static const char cmd_pipeline_port_in_enable_help[] =
2374 "pipeline <pipeline_name> port in <port_id> enable\n";
2375
2376 static void
2377 cmd_pipeline_port_in_enable(char **tokens,
2378         uint32_t n_tokens,
2379         char *out,
2380         size_t out_size)
2381 {
2382         char *pipeline_name;
2383         uint32_t port_id;
2384         int status;
2385
2386         if (n_tokens != 6) {
2387                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2388                 return;
2389         }
2390
2391         pipeline_name = tokens[1];
2392
2393         if (strcmp(tokens[2], "port") != 0) {
2394                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2395                 return;
2396         }
2397
2398         if (strcmp(tokens[3], "in") != 0) {
2399                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2400                 return;
2401         }
2402
2403         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2404                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2405                 return;
2406         }
2407
2408         if (strcmp(tokens[5], "enable") != 0) {
2409                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2410                 return;
2411         }
2412
2413         status = pipeline_port_in_enable(pipeline_name, port_id);
2414         if (status) {
2415                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2416                 return;
2417         }
2418 }
2419
2420
2421 static const char cmd_pipeline_port_in_disable_help[] =
2422 "pipeline <pipeline_name> port in <port_id> disable\n";
2423
2424 static void
2425 cmd_pipeline_port_in_disable(char **tokens,
2426         uint32_t n_tokens,
2427         char *out,
2428         size_t out_size)
2429 {
2430         char *pipeline_name;
2431         uint32_t port_id;
2432         int status;
2433
2434         if (n_tokens != 6) {
2435                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2436                 return;
2437         }
2438
2439         pipeline_name = tokens[1];
2440
2441         if (strcmp(tokens[2], "port") != 0) {
2442                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2443                 return;
2444         }
2445
2446         if (strcmp(tokens[3], "in") != 0) {
2447                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2448                 return;
2449         }
2450
2451         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2452                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2453                 return;
2454         }
2455
2456         if (strcmp(tokens[5], "disable") != 0) {
2457                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2458                 return;
2459         }
2460
2461         status = pipeline_port_in_disable(pipeline_name, port_id);
2462         if (status) {
2463                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2464                 return;
2465         }
2466 }
2467
2468
2469 static const char cmd_pipeline_port_out_stats_help[] =
2470 "pipeline <pipeline_name> port out <port_id> stats read [clear]\n";
2471
2472 #define MSG_PIPELINE_PORT_OUT_STATS                        \
2473         "Pkts in: %" PRIu64 "\n"                           \
2474         "Pkts dropped by AH: %" PRIu64 "\n"                \
2475         "Pkts dropped by other: %" PRIu64 "\n"
2476
2477 static void
2478 cmd_pipeline_port_out_stats(char **tokens,
2479         uint32_t n_tokens,
2480         char *out,
2481         size_t out_size)
2482 {
2483         struct rte_pipeline_port_out_stats stats;
2484         char *pipeline_name;
2485         uint32_t port_id;
2486         int clear, status;
2487
2488         if ((n_tokens != 7) && (n_tokens != 8)) {
2489                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2490                 return;
2491         }
2492
2493         pipeline_name = tokens[1];
2494
2495         if (strcmp(tokens[2], "port") != 0) {
2496                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2497                 return;
2498         }
2499
2500         if (strcmp(tokens[3], "out") != 0) {
2501                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2502                 return;
2503         }
2504
2505         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2506                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2507                 return;
2508         }
2509
2510         if (strcmp(tokens[5], "stats") != 0) {
2511                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2512                 return;
2513         }
2514
2515         if (strcmp(tokens[6], "read") != 0) {
2516                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2517                 return;
2518         }
2519
2520         clear = 0;
2521         if (n_tokens == 8) {
2522                 if (strcmp(tokens[7], "clear") != 0) {
2523                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2524                         return;
2525                 }
2526
2527                 clear = 1;
2528         }
2529
2530         status = pipeline_port_out_stats_read(pipeline_name,
2531                 port_id,
2532                 &stats,
2533                 clear);
2534         if (status) {
2535                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2536                 return;
2537         }
2538
2539         snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
2540                 stats.stats.n_pkts_in,
2541                 stats.n_pkts_dropped_by_ah,
2542                 stats.stats.n_pkts_drop);
2543 }
2544
2545
2546 static const char cmd_pipeline_table_stats_help[] =
2547 "pipeline <pipeline_name> table <table_id> stats read [clear]\n";
2548
2549 #define MSG_PIPELINE_TABLE_STATS                                     \
2550         "Pkts in: %" PRIu64 "\n"                                     \
2551         "Pkts in with lookup miss: %" PRIu64 "\n"                    \
2552         "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
2553         "Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
2554         "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
2555         "Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
2556
2557 static void
2558 cmd_pipeline_table_stats(char **tokens,
2559         uint32_t n_tokens,
2560         char *out,
2561         size_t out_size)
2562 {
2563         struct rte_pipeline_table_stats stats;
2564         char *pipeline_name;
2565         uint32_t table_id;
2566         int clear, status;
2567
2568         if ((n_tokens != 6) && (n_tokens != 7)) {
2569                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2570                 return;
2571         }
2572
2573         pipeline_name = tokens[1];
2574
2575         if (strcmp(tokens[2], "table") != 0) {
2576                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2577                 return;
2578         }
2579
2580         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
2581                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2582                 return;
2583         }
2584
2585         if (strcmp(tokens[4], "stats") != 0) {
2586                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2587                 return;
2588         }
2589
2590         if (strcmp(tokens[5], "read") != 0) {
2591                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2592                 return;
2593         }
2594
2595         clear = 0;
2596         if (n_tokens == 7) {
2597                 if (strcmp(tokens[6], "clear") != 0) {
2598                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2599                         return;
2600                 }
2601
2602                 clear = 1;
2603         }
2604
2605         status = pipeline_table_stats_read(pipeline_name,
2606                 table_id,
2607                 &stats,
2608                 clear);
2609         if (status) {
2610                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2611                 return;
2612         }
2613
2614         snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
2615                 stats.stats.n_pkts_in,
2616                 stats.stats.n_pkts_lookup_miss,
2617                 stats.n_pkts_dropped_by_lkp_hit_ah,
2618                 stats.n_pkts_dropped_lkp_hit,
2619                 stats.n_pkts_dropped_by_lkp_miss_ah,
2620                 stats.n_pkts_dropped_lkp_miss);
2621 }
2622
2623 /**
2624  * <match> ::=
2625  *
2626  * match
2627  *    acl
2628  *       priority <priority>
2629  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
2630  *       <sp0> <sp1> <dp0> <dp1> <proto>
2631  *    | array <pos>
2632  *    | hash
2633  *       raw <key>
2634  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2635  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2636  *       | ipv4_addr <addr>
2637  *       | ipv6_addr <addr>
2638  *       | qinq <svlan> <cvlan>
2639  *    | lpm
2640  *       ipv4 | ipv6 <addr> <depth>
2641  */
2642 struct pkt_key_qinq {
2643         uint16_t ethertype_svlan;
2644         uint16_t svlan;
2645         uint16_t ethertype_cvlan;
2646         uint16_t cvlan;
2647 } __attribute__((__packed__));
2648
2649 struct pkt_key_ipv4_5tuple {
2650         uint8_t time_to_live;
2651         uint8_t proto;
2652         uint16_t hdr_checksum;
2653         uint32_t sa;
2654         uint32_t da;
2655         uint16_t sp;
2656         uint16_t dp;
2657 } __attribute__((__packed__));
2658
2659 struct pkt_key_ipv6_5tuple {
2660         uint16_t payload_length;
2661         uint8_t proto;
2662         uint8_t hop_limit;
2663         uint8_t sa[16];
2664         uint8_t da[16];
2665         uint16_t sp;
2666         uint16_t dp;
2667 } __attribute__((__packed__));
2668
2669 struct pkt_key_ipv4_addr {
2670         uint32_t addr;
2671 } __attribute__((__packed__));
2672
2673 struct pkt_key_ipv6_addr {
2674         uint8_t addr[16];
2675 } __attribute__((__packed__));
2676
2677 static uint32_t
2678 parse_match(char **tokens,
2679         uint32_t n_tokens,
2680         char *out,
2681         size_t out_size,
2682         struct table_rule_match *m)
2683 {
2684         memset(m, 0, sizeof(*m));
2685
2686         if (n_tokens < 2)
2687                 return 0;
2688
2689         if (strcmp(tokens[0], "match") != 0) {
2690                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2691                 return 0;
2692         }
2693
2694         if (strcmp(tokens[1], "acl") == 0) {
2695                 if (n_tokens < 14) {
2696                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2697                         return 0;
2698                 }
2699
2700                 m->match_type = TABLE_ACL;
2701
2702                 if (strcmp(tokens[2], "priority") != 0) {
2703                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
2704                         return 0;
2705                 }
2706
2707                 if (parser_read_uint32(&m->match.acl.priority,
2708                         tokens[3]) != 0) {
2709                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
2710                         return 0;
2711                 }
2712
2713                 if (strcmp(tokens[4], "ipv4") == 0) {
2714                         struct in_addr saddr, daddr;
2715
2716                         m->match.acl.ip_version = 1;
2717
2718                         if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
2719                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2720                                 return 0;
2721                         }
2722                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
2723
2724                         if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
2725                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2726                                 return 0;
2727                         }
2728                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
2729                 } else if (strcmp(tokens[4], "ipv6") == 0) {
2730                         struct in6_addr saddr, daddr;
2731
2732                         m->match.acl.ip_version = 0;
2733
2734                         if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
2735                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2736                                 return 0;
2737                         }
2738                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2739
2740                         if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2741                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2742                                 return 0;
2743                         }
2744                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
2745                 } else {
2746                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2747                                 "ipv4 or ipv6");
2748                         return 0;
2749                 }
2750
2751                 if (parser_read_uint32(&m->match.acl.sa_depth,
2752                         tokens[6]) != 0) {
2753                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
2754                         return 0;
2755                 }
2756
2757                 if (parser_read_uint32(&m->match.acl.da_depth,
2758                         tokens[8]) != 0) {
2759                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
2760                         return 0;
2761                 }
2762
2763                 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
2764                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
2765                         return 0;
2766                 }
2767
2768                 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
2769                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
2770                         return 0;
2771                 }
2772
2773                 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
2774                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
2775                         return 0;
2776                 }
2777
2778                 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
2779                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
2780                         return 0;
2781                 }
2782
2783                 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
2784                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
2785                         return 0;
2786                 }
2787
2788                 m->match.acl.proto_mask = 0xff;
2789
2790                 return 14;
2791         } /* acl */
2792
2793         if (strcmp(tokens[1], "array") == 0) {
2794                 if (n_tokens < 3) {
2795                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2796                         return 0;
2797                 }
2798
2799                 m->match_type = TABLE_ARRAY;
2800
2801                 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
2802                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
2803                         return 0;
2804                 }
2805
2806                 return 3;
2807         } /* array */
2808
2809         if (strcmp(tokens[1], "hash") == 0) {
2810                 if (n_tokens < 3) {
2811                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2812                         return 0;
2813                 }
2814
2815                 m->match_type = TABLE_HASH;
2816
2817                 if (strcmp(tokens[2], "raw") == 0) {
2818                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
2819
2820                         if (n_tokens < 4) {
2821                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2822                                         tokens[0]);
2823                                 return 0;
2824                         }
2825
2826                         if (parse_hex_string(tokens[3],
2827                                 m->match.hash.key, &key_size) != 0) {
2828                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
2829                                 return 0;
2830                         }
2831
2832                         return 4;
2833                 } /* hash raw */
2834
2835                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
2836                         struct pkt_key_ipv4_5tuple *ipv4 =
2837                                 (struct pkt_key_ipv4_5tuple *) m->match.hash.key;
2838                         struct in_addr saddr, daddr;
2839                         uint16_t sp, dp;
2840                         uint8_t proto;
2841
2842                         if (n_tokens < 8) {
2843                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2844                                         tokens[0]);
2845                                 return 0;
2846                         }
2847
2848                         if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
2849                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2850                                 return 0;
2851                         }
2852
2853                         if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
2854                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2855                                 return 0;
2856                         }
2857
2858                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2859                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2860                                 return 0;
2861                         }
2862
2863                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2864                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2865                                 return 0;
2866                         }
2867
2868                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2869                                 snprintf(out, out_size, MSG_ARG_INVALID,
2870                                         "proto");
2871                                 return 0;
2872                         }
2873
2874                         ipv4->sa = saddr.s_addr;
2875                         ipv4->da = daddr.s_addr;
2876                         ipv4->sp = rte_cpu_to_be_16(sp);
2877                         ipv4->dp = rte_cpu_to_be_16(dp);
2878                         ipv4->proto = proto;
2879
2880                         return 8;
2881                 } /* hash ipv4_5tuple */
2882
2883                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
2884                         struct pkt_key_ipv6_5tuple *ipv6 =
2885                                 (struct pkt_key_ipv6_5tuple *) m->match.hash.key;
2886                         struct in6_addr saddr, daddr;
2887                         uint16_t sp, dp;
2888                         uint8_t proto;
2889
2890                         if (n_tokens < 8) {
2891                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2892                                         tokens[0]);
2893                                 return 0;
2894                         }
2895
2896                         if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
2897                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2898                                 return 0;
2899                         }
2900
2901                         if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
2902                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2903                                 return 0;
2904                         }
2905
2906                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2907                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2908                                 return 0;
2909                         }
2910
2911                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2912                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2913                                 return 0;
2914                         }
2915
2916                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2917                                 snprintf(out, out_size, MSG_ARG_INVALID,
2918                                         "proto");
2919                                 return 0;
2920                         }
2921
2922                         memcpy(ipv6->sa, saddr.s6_addr, 16);
2923                         memcpy(ipv6->da, daddr.s6_addr, 16);
2924                         ipv6->sp = rte_cpu_to_be_16(sp);
2925                         ipv6->dp = rte_cpu_to_be_16(dp);
2926                         ipv6->proto = proto;
2927
2928                         return 8;
2929                 } /* hash ipv6_5tuple */
2930
2931                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
2932                         struct pkt_key_ipv4_addr *ipv4_addr =
2933                                 (struct pkt_key_ipv4_addr *) m->match.hash.key;
2934                         struct in_addr addr;
2935
2936                         if (n_tokens < 4) {
2937                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2938                                         tokens[0]);
2939                                 return 0;
2940                         }
2941
2942                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2943                                 snprintf(out, out_size, MSG_ARG_INVALID,
2944                                         "addr");
2945                                 return 0;
2946                         }
2947
2948                         ipv4_addr->addr = addr.s_addr;
2949
2950                         return 4;
2951                 } /* hash ipv4_addr */
2952
2953                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
2954                         struct pkt_key_ipv6_addr *ipv6_addr =
2955                                 (struct pkt_key_ipv6_addr *) m->match.hash.key;
2956                         struct in6_addr addr;
2957
2958                         if (n_tokens < 4) {
2959                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2960                                         tokens[0]);
2961                                 return 0;
2962                         }
2963
2964                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2965                                 snprintf(out, out_size, MSG_ARG_INVALID,
2966                                         "addr");
2967                                 return 0;
2968                         }
2969
2970                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
2971
2972                         return 4;
2973                 } /* hash ipv6_5tuple */
2974
2975                 if (strcmp(tokens[2], "qinq") == 0) {
2976                         struct pkt_key_qinq *qinq =
2977                                 (struct pkt_key_qinq *) m->match.hash.key;
2978                         uint16_t svlan, cvlan;
2979
2980                         if (n_tokens < 5) {
2981                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2982                                         tokens[0]);
2983                                 return 0;
2984                         }
2985
2986                         if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
2987                                 (svlan > 0xFFF)) {
2988                                 snprintf(out, out_size, MSG_ARG_INVALID,
2989                                         "svlan");
2990                                 return 0;
2991                         }
2992
2993                         if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
2994                                 (cvlan > 0xFFF)) {
2995                                 snprintf(out, out_size, MSG_ARG_INVALID,
2996                                         "cvlan");
2997                                 return 0;
2998                         }
2999
3000                         qinq->svlan = rte_cpu_to_be_16(svlan);
3001                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
3002
3003                         return 5;
3004                 } /* hash qinq */
3005
3006                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3007                 return 0;
3008         } /* hash */
3009
3010         if (strcmp(tokens[1], "lpm") == 0) {
3011                 if (n_tokens < 5) {
3012                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3013                         return 0;
3014                 }
3015
3016                 m->match_type = TABLE_LPM;
3017
3018                 if (strcmp(tokens[2], "ipv4") == 0) {
3019                         struct in_addr addr;
3020
3021                         m->match.lpm.ip_version = 1;
3022
3023                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
3024                                 snprintf(out, out_size, MSG_ARG_INVALID,
3025                                         "addr");
3026                                 return 0;
3027                         }
3028
3029                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3030                 } else if (strcmp(tokens[2], "ipv6") == 0) {
3031                         struct in6_addr addr;
3032
3033                         m->match.lpm.ip_version = 0;
3034
3035                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
3036                                 snprintf(out, out_size, MSG_ARG_INVALID,
3037                                         "addr");
3038                                 return 0;
3039                         }
3040
3041                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
3042                 } else {
3043                         snprintf(out, out_size, MSG_ARG_MISMATCH,
3044                                 "ipv4 or ipv6");
3045                         return 0;
3046                 }
3047
3048                 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
3049                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
3050                         return 0;
3051                 }
3052
3053                 return 5;
3054         } /* lpm */
3055
3056         snprintf(out, out_size, MSG_ARG_MISMATCH,
3057                 "acl or array or hash or lpm");
3058         return 0;
3059 }
3060
3061 /**
3062  * table_action ::=
3063  *
3064  * action
3065  *    fwd
3066  *       drop
3067  *       | port <port_id>
3068  *       | meta
3069  *       | table <table_id>
3070  *    [balance <out0> ... <out7>]
3071  *    [meter
3072  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3073  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3074  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3075  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
3076  *    [tm subport <subport_id> pipe <pipe_id>]
3077  *    [encap
3078  *       ether <da> <sa>
3079  *       | vlan <da> <sa> <pcp> <dei> <vid>
3080  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
3081  *       | mpls unicast | multicast
3082  *          <da> <sa>
3083  *          label0 <label> <tc> <ttl>
3084  *          [label1 <label> <tc> <ttl>
3085  *          [label2 <label> <tc> <ttl>
3086  *          [label3 <label> <tc> <ttl>]]]
3087  *       | pppoe <da> <sa> <session_id>
3088  *       | vxlan ether <da> <sa>
3089  *          [vlan <pcp> <dei> <vid>]
3090  *          ipv4 <sa> <da> <dscp> <ttl>
3091  *          | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit>
3092  *          udp <sp> <dp>
3093  *          vxlan <vni>]
3094  *    [nat ipv4 | ipv6 <addr> <port>]
3095  *    [ttl dec | keep]
3096  *    [stats]
3097  *    [time]
3098  *    [sym_crypto
3099  *       encrypt | decrypt
3100  *       type
3101  *       | cipher
3102  *          cipher_algo <algo> cipher_key <key> cipher_iv <iv>
3103  *       | cipher_auth
3104  *          cipher_algo <algo> cipher_key <key> cipher_iv <iv>
3105  *          auth_algo <algo> auth_key <key> digest_size <size>
3106  *       | aead
3107  *          aead_algo <algo> aead_key <key> aead_iv <iv> aead_aad <aad>
3108  *          digest_size <size>
3109  *       data_offset <data_offset>]
3110  *
3111  * where:
3112  *    <pa> ::= g | y | r | drop
3113  */
3114 static uint32_t
3115 parse_table_action_fwd(char **tokens,
3116         uint32_t n_tokens,
3117         struct table_rule_action *a)
3118 {
3119         if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
3120                 return 0;
3121
3122         tokens++;
3123         n_tokens--;
3124
3125         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
3126                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
3127                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3128                 return 1 + 1;
3129         }
3130
3131         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
3132                 uint32_t id;
3133
3134                 if ((n_tokens < 2) ||
3135                         parser_read_uint32(&id, tokens[1]))
3136                         return 0;
3137
3138                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
3139                 a->fwd.id = id;
3140                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3141                 return 1 + 2;
3142         }
3143
3144         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
3145                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3146                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3147                 return 1 + 1;
3148         }
3149
3150         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
3151                 uint32_t id;
3152
3153                 if ((n_tokens < 2) ||
3154                         parser_read_uint32(&id, tokens[1]))
3155                         return 0;
3156
3157                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
3158                 a->fwd.id = id;
3159                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3160                 return 1 + 2;
3161         }
3162
3163         return 0;
3164 }
3165
3166 static uint32_t
3167 parse_table_action_balance(char **tokens,
3168         uint32_t n_tokens,
3169         struct table_rule_action *a)
3170 {
3171         uint32_t i;
3172
3173         if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0))
3174                 return 0;
3175
3176         tokens++;
3177         n_tokens--;
3178
3179         if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE)
3180                 return 0;
3181
3182         for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++)
3183                 if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
3184                         return 0;
3185
3186         a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
3187         return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE;
3188
3189 }
3190
3191 static int
3192 parse_policer_action(char *token, enum rte_table_action_policer *a)
3193 {
3194         if (strcmp(token, "g") == 0) {
3195                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
3196                 return 0;
3197         }
3198
3199         if (strcmp(token, "y") == 0) {
3200                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
3201                 return 0;
3202         }
3203
3204         if (strcmp(token, "r") == 0) {
3205                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
3206                 return 0;
3207         }
3208
3209         if (strcmp(token, "drop") == 0) {
3210                 *a = RTE_TABLE_ACTION_POLICER_DROP;
3211                 return 0;
3212         }
3213
3214         return -1;
3215 }
3216
3217 static uint32_t
3218 parse_table_action_meter_tc(char **tokens,
3219         uint32_t n_tokens,
3220         struct rte_table_action_mtr_tc_params *mtr)
3221 {
3222         if ((n_tokens < 9) ||
3223                 strcmp(tokens[0], "meter") ||
3224                 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
3225                 strcmp(tokens[2], "policer") ||
3226                 strcmp(tokens[3], "g") ||
3227                 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
3228                 strcmp(tokens[5], "y") ||
3229                 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
3230                 strcmp(tokens[7], "r") ||
3231                 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
3232                 return 0;
3233
3234         return 9;
3235 }
3236
3237 static uint32_t
3238 parse_table_action_meter(char **tokens,
3239         uint32_t n_tokens,
3240         struct table_rule_action *a)
3241 {
3242         if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
3243                 return 0;
3244
3245         tokens++;
3246         n_tokens--;
3247
3248         if ((n_tokens < 10) ||
3249                 strcmp(tokens[0], "tc0") ||
3250                 (parse_table_action_meter_tc(tokens + 1,
3251                         n_tokens - 1,
3252                         &a->mtr.mtr[0]) == 0))
3253                 return 0;
3254
3255         tokens += 10;
3256         n_tokens -= 10;
3257
3258         if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
3259                 a->mtr.tc_mask = 1;
3260                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3261                 return 1 + 10;
3262         }
3263
3264         if ((n_tokens < 30) ||
3265                 (parse_table_action_meter_tc(tokens + 1,
3266                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
3267                 strcmp(tokens[10], "tc2") ||
3268                 (parse_table_action_meter_tc(tokens + 11,
3269                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
3270                 strcmp(tokens[20], "tc3") ||
3271                 (parse_table_action_meter_tc(tokens + 21,
3272                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
3273                 return 0;
3274
3275         a->mtr.tc_mask = 0xF;
3276         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3277         return 1 + 10 + 3 * 10;
3278 }
3279
3280 static uint32_t
3281 parse_table_action_tm(char **tokens,
3282         uint32_t n_tokens,
3283         struct table_rule_action *a)
3284 {
3285         uint32_t subport_id, pipe_id;
3286
3287         if ((n_tokens < 5) ||
3288                 strcmp(tokens[0], "tm") ||
3289                 strcmp(tokens[1], "subport") ||
3290                 parser_read_uint32(&subport_id, tokens[2]) ||
3291                 strcmp(tokens[3], "pipe") ||
3292                 parser_read_uint32(&pipe_id, tokens[4]))
3293                 return 0;
3294
3295         a->tm.subport_id = subport_id;
3296         a->tm.pipe_id = pipe_id;
3297         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
3298         return 5;
3299 }
3300
3301 static uint32_t
3302 parse_table_action_encap(char **tokens,
3303         uint32_t n_tokens,
3304         struct table_rule_action *a)
3305 {
3306         if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
3307                 return 0;
3308
3309         tokens++;
3310         n_tokens--;
3311
3312         /* ether */
3313         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
3314                 if ((n_tokens < 3) ||
3315                         parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
3316                         parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
3317                         return 0;
3318
3319                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
3320                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3321                 return 1 + 3;
3322         }
3323
3324         /* vlan */
3325         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
3326                 uint32_t pcp, dei, vid;
3327
3328                 if ((n_tokens < 6) ||
3329                         parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
3330                         parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
3331                         parser_read_uint32(&pcp, tokens[3]) ||
3332                         (pcp > 0x7) ||
3333                         parser_read_uint32(&dei, tokens[4]) ||
3334                         (dei > 0x1) ||
3335                         parser_read_uint32(&vid, tokens[5]) ||
3336                         (vid > 0xFFF))
3337                         return 0;
3338
3339                 a->encap.vlan.vlan.pcp = pcp & 0x7;
3340                 a->encap.vlan.vlan.dei = dei & 0x1;
3341                 a->encap.vlan.vlan.vid = vid & 0xFFF;
3342                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
3343                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3344                 return 1 + 6;
3345         }
3346
3347         /* qinq */
3348         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
3349                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
3350                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3351
3352                 if ((n_tokens < 9) ||
3353                         parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
3354                         parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
3355                         parser_read_uint32(&svlan_pcp, tokens[3]) ||
3356                         (svlan_pcp > 0x7) ||
3357                         parser_read_uint32(&svlan_dei, tokens[4]) ||
3358                         (svlan_dei > 0x1) ||
3359                         parser_read_uint32(&svlan_vid, tokens[5]) ||
3360                         (svlan_vid > 0xFFF) ||
3361                         parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3362                         (cvlan_pcp > 0x7) ||
3363                         parser_read_uint32(&cvlan_dei, tokens[7]) ||
3364                         (cvlan_dei > 0x1) ||
3365                         parser_read_uint32(&cvlan_vid, tokens[8]) ||
3366                         (cvlan_vid > 0xFFF))
3367                         return 0;
3368
3369                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
3370                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
3371                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
3372                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
3373                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
3374                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
3375                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
3376                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3377                 return 1 + 9;
3378         }
3379
3380         /* mpls */
3381         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
3382                 uint32_t label, tc, ttl;
3383
3384                 if (n_tokens < 8)
3385                         return 0;
3386
3387                 if (strcmp(tokens[1], "unicast") == 0)
3388                         a->encap.mpls.unicast = 1;
3389                 else if (strcmp(tokens[1], "multicast") == 0)
3390                         a->encap.mpls.unicast = 0;
3391                 else
3392                         return 0;
3393
3394                 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
3395                         parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
3396                         strcmp(tokens[4], "label0") ||
3397                         parser_read_uint32(&label, tokens[5]) ||
3398                         (label > 0xFFFFF) ||
3399                         parser_read_uint32(&tc, tokens[6]) ||
3400                         (tc > 0x7) ||
3401                         parser_read_uint32(&ttl, tokens[7]) ||
3402                         (ttl > 0x3F))
3403                         return 0;
3404
3405                 a->encap.mpls.mpls[0].label = label;
3406                 a->encap.mpls.mpls[0].tc = tc;
3407                 a->encap.mpls.mpls[0].ttl = ttl;
3408
3409                 tokens += 8;
3410                 n_tokens -= 8;
3411
3412                 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
3413                         a->encap.mpls.mpls_count = 1;
3414                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3415                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3416                         return 1 + 8;
3417                 }
3418
3419                 if ((n_tokens < 4) ||
3420                         parser_read_uint32(&label, tokens[1]) ||
3421                         (label > 0xFFFFF) ||
3422                         parser_read_uint32(&tc, tokens[2]) ||
3423                         (tc > 0x7) ||
3424                         parser_read_uint32(&ttl, tokens[3]) ||
3425                         (ttl > 0x3F))
3426                         return 0;
3427
3428                 a->encap.mpls.mpls[1].label = label;
3429                 a->encap.mpls.mpls[1].tc = tc;
3430                 a->encap.mpls.mpls[1].ttl = ttl;
3431
3432                 tokens += 4;
3433                 n_tokens -= 4;
3434
3435                 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
3436                         a->encap.mpls.mpls_count = 2;
3437                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3438                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3439                         return 1 + 8 + 4;
3440                 }
3441
3442                 if ((n_tokens < 4) ||
3443                         parser_read_uint32(&label, tokens[1]) ||
3444                         (label > 0xFFFFF) ||
3445                         parser_read_uint32(&tc, tokens[2]) ||
3446                         (tc > 0x7) ||
3447                         parser_read_uint32(&ttl, tokens[3]) ||
3448                         (ttl > 0x3F))
3449                         return 0;
3450
3451                 a->encap.mpls.mpls[2].label = label;
3452                 a->encap.mpls.mpls[2].tc = tc;
3453                 a->encap.mpls.mpls[2].ttl = ttl;
3454
3455                 tokens += 4;
3456                 n_tokens -= 4;
3457
3458                 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
3459                         a->encap.mpls.mpls_count = 3;
3460                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3461                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3462                         return 1 + 8 + 4 + 4;
3463                 }
3464
3465                 if ((n_tokens < 4) ||
3466                         parser_read_uint32(&label, tokens[1]) ||
3467                         (label > 0xFFFFF) ||
3468                         parser_read_uint32(&tc, tokens[2]) ||
3469                         (tc > 0x7) ||
3470                         parser_read_uint32(&ttl, tokens[3]) ||
3471                         (ttl > 0x3F))
3472                         return 0;
3473
3474                 a->encap.mpls.mpls[3].label = label;
3475                 a->encap.mpls.mpls[3].tc = tc;
3476                 a->encap.mpls.mpls[3].ttl = ttl;
3477
3478                 a->encap.mpls.mpls_count = 4;
3479                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3480                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3481                 return 1 + 8 + 4 + 4 + 4;
3482         }
3483
3484         /* pppoe */
3485         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3486                 if ((n_tokens < 4) ||
3487                         parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3488                         parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3489                         parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3490                                 tokens[3]))
3491                         return 0;
3492
3493                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3494                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3495                 return 1 + 4;
3496         }
3497
3498         /* vxlan */
3499         if (n_tokens && (strcmp(tokens[0], "vxlan") == 0)) {
3500                 uint32_t n = 0;
3501
3502                 n_tokens--;
3503                 tokens++;
3504                 n++;
3505
3506                 /* ether <da> <sa> */
3507                 if ((n_tokens < 3) ||
3508                         strcmp(tokens[0], "ether") ||
3509                         parse_mac_addr(tokens[1], &a->encap.vxlan.ether.da) ||
3510                         parse_mac_addr(tokens[2], &a->encap.vxlan.ether.sa))
3511                         return 0;
3512
3513                 n_tokens -= 3;
3514                 tokens += 3;
3515                 n += 3;
3516
3517                 /* [vlan <pcp> <dei> <vid>] */
3518                 if (strcmp(tokens[0], "vlan") == 0) {
3519                         uint32_t pcp, dei, vid;
3520
3521                         if ((n_tokens < 4) ||
3522                                 parser_read_uint32(&pcp, tokens[1]) ||
3523                                 (pcp > 7) ||
3524                                 parser_read_uint32(&dei, tokens[2]) ||
3525                                 (dei > 1) ||
3526                                 parser_read_uint32(&vid, tokens[3]) ||
3527                                 (vid > 0xFFF))
3528                                 return 0;
3529
3530                         a->encap.vxlan.vlan.pcp = pcp;
3531                         a->encap.vxlan.vlan.dei = dei;
3532                         a->encap.vxlan.vlan.vid = vid;
3533
3534                         n_tokens -= 4;
3535                         tokens += 4;
3536                         n += 4;
3537                 }
3538
3539                 /* ipv4 <sa> <da> <dscp> <ttl>
3540                    | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> */
3541                 if (strcmp(tokens[0], "ipv4") == 0) {
3542                         struct in_addr sa, da;
3543                         uint8_t dscp, ttl;
3544
3545                         if ((n_tokens < 5) ||
3546                                 parse_ipv4_addr(tokens[1], &sa) ||
3547                                 parse_ipv4_addr(tokens[2], &da) ||
3548                                 parser_read_uint8(&dscp, tokens[3]) ||
3549                                 (dscp > 64) ||
3550                                 parser_read_uint8(&ttl, tokens[4]))
3551                                 return 0;
3552
3553                         a->encap.vxlan.ipv4.sa = rte_be_to_cpu_32(sa.s_addr);
3554                         a->encap.vxlan.ipv4.da = rte_be_to_cpu_32(da.s_addr);
3555                         a->encap.vxlan.ipv4.dscp = dscp;
3556                         a->encap.vxlan.ipv4.ttl = ttl;
3557
3558                         n_tokens -= 5;
3559                         tokens += 5;
3560                         n += 5;
3561                 } else if (strcmp(tokens[0], "ipv6") == 0) {
3562                         struct in6_addr sa, da;
3563                         uint32_t flow_label;
3564                         uint8_t dscp, hop_limit;
3565
3566                         if ((n_tokens < 6) ||
3567                                 parse_ipv6_addr(tokens[1], &sa) ||
3568                                 parse_ipv6_addr(tokens[2], &da) ||
3569                                 parser_read_uint32(&flow_label, tokens[3]) ||
3570                                 parser_read_uint8(&dscp, tokens[4]) ||
3571                                 (dscp > 64) ||
3572                                 parser_read_uint8(&hop_limit, tokens[5]))
3573                                 return 0;
3574
3575                         memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16);
3576                         memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16);
3577                         a->encap.vxlan.ipv6.flow_label = flow_label;
3578                         a->encap.vxlan.ipv6.dscp = dscp;
3579                         a->encap.vxlan.ipv6.hop_limit = hop_limit;
3580
3581                         n_tokens -= 6;
3582                         tokens += 6;
3583                         n += 6;
3584                 } else
3585                         return 0;
3586
3587                 /* udp <sp> <dp> */
3588                 if ((n_tokens < 3) ||
3589                         strcmp(tokens[0], "udp") ||
3590                         parser_read_uint16(&a->encap.vxlan.udp.sp, tokens[1]) ||
3591                         parser_read_uint16(&a->encap.vxlan.udp.dp, tokens[2]))
3592                         return 0;
3593
3594                 n_tokens -= 3;
3595                 tokens += 3;
3596                 n += 3;
3597
3598                 /* vxlan <vni> */
3599                 if ((n_tokens < 2) ||
3600                         strcmp(tokens[0], "vxlan") ||
3601                         parser_read_uint32(&a->encap.vxlan.vxlan.vni, tokens[1]) ||
3602                         (a->encap.vxlan.vxlan.vni > 0xFFFFFF))
3603                         return 0;
3604
3605                 n_tokens -= 2;
3606                 tokens += 2;
3607                 n += 2;
3608
3609                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN;
3610                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3611                 return 1 + n;
3612         }
3613
3614         return 0;
3615 }
3616
3617 static uint32_t
3618 parse_table_action_nat(char **tokens,
3619         uint32_t n_tokens,
3620         struct table_rule_action *a)
3621 {
3622         if ((n_tokens < 4) ||
3623                 strcmp(tokens[0], "nat"))
3624                 return 0;
3625
3626         if (strcmp(tokens[1], "ipv4") == 0) {
3627                 struct in_addr addr;
3628                 uint16_t port;
3629
3630                 if (parse_ipv4_addr(tokens[2], &addr) ||
3631                         parser_read_uint16(&port, tokens[3]))
3632                         return 0;
3633
3634                 a->nat.ip_version = 1;
3635                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3636                 a->nat.port = port;
3637                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3638                 return 4;
3639         }
3640
3641         if (strcmp(tokens[1], "ipv6") == 0) {
3642                 struct in6_addr addr;
3643                 uint16_t port;
3644
3645                 if (parse_ipv6_addr(tokens[2], &addr) ||
3646                         parser_read_uint16(&port, tokens[3]))
3647                         return 0;
3648
3649                 a->nat.ip_version = 0;
3650                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3651                 a->nat.port = port;
3652                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3653                 return 4;
3654         }
3655
3656         return 0;
3657 }
3658
3659 static uint32_t
3660 parse_table_action_ttl(char **tokens,
3661         uint32_t n_tokens,
3662         struct table_rule_action *a)
3663 {
3664         if ((n_tokens < 2) ||
3665                 strcmp(tokens[0], "ttl"))
3666                 return 0;
3667
3668         if (strcmp(tokens[1], "dec") == 0)
3669                 a->ttl.decrement = 1;
3670         else if (strcmp(tokens[1], "keep") == 0)
3671                 a->ttl.decrement = 0;
3672         else
3673                 return 0;
3674
3675         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
3676         return 2;
3677 }
3678
3679 static uint32_t
3680 parse_table_action_stats(char **tokens,
3681         uint32_t n_tokens,
3682         struct table_rule_action *a)
3683 {
3684         if ((n_tokens < 1) ||
3685                 strcmp(tokens[0], "stats"))
3686                 return 0;
3687
3688         a->stats.n_packets = 0;
3689         a->stats.n_bytes = 0;
3690         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
3691         return 1;
3692 }
3693
3694 static uint32_t
3695 parse_table_action_time(char **tokens,
3696         uint32_t n_tokens,
3697         struct table_rule_action *a)
3698 {
3699         if ((n_tokens < 1) ||
3700                 strcmp(tokens[0], "time"))
3701                 return 0;
3702
3703         a->time.time = rte_rdtsc();
3704         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
3705         return 1;
3706 }
3707
3708 static void
3709 parse_free_sym_crypto_param_data(struct rte_table_action_sym_crypto_params *p)
3710 {
3711         struct rte_crypto_sym_xform *xform[2] = {NULL};
3712         uint32_t i;
3713
3714         xform[0] = p->xform;
3715         if (xform[0])
3716                 xform[1] = xform[0]->next;
3717
3718         for (i = 0; i < 2; i++) {
3719                 if (xform[i] == NULL)
3720                         continue;
3721
3722                 switch (xform[i]->type) {
3723                 case RTE_CRYPTO_SYM_XFORM_CIPHER:
3724                         if (xform[i]->cipher.key.data)
3725                                 free(xform[i]->cipher.key.data);
3726                         if (p->cipher_auth.cipher_iv.val)
3727                                 free(p->cipher_auth.cipher_iv.val);
3728                         if (p->cipher_auth.cipher_iv_update.val)
3729                                 free(p->cipher_auth.cipher_iv_update.val);
3730                         break;
3731                 case RTE_CRYPTO_SYM_XFORM_AUTH:
3732                         if (xform[i]->auth.key.data)
3733                                 free(xform[i]->cipher.key.data);
3734                         if (p->cipher_auth.auth_iv.val)
3735                                 free(p->cipher_auth.cipher_iv.val);
3736                         if (p->cipher_auth.auth_iv_update.val)
3737                                 free(p->cipher_auth.cipher_iv_update.val);
3738                         break;
3739                 case RTE_CRYPTO_SYM_XFORM_AEAD:
3740                         if (xform[i]->aead.key.data)
3741                                 free(xform[i]->cipher.key.data);
3742                         if (p->aead.iv.val)
3743                                 free(p->aead.iv.val);
3744                         if (p->aead.aad.val)
3745                                 free(p->aead.aad.val);
3746                         break;
3747                 default:
3748                         continue;
3749                 }
3750         }
3751
3752 }
3753
3754 static struct rte_crypto_sym_xform *
3755 parse_table_action_cipher(struct rte_table_action_sym_crypto_params *p,
3756                 char **tokens, uint32_t n_tokens, uint32_t encrypt,
3757                 uint32_t *used_n_tokens)
3758 {
3759         struct rte_crypto_sym_xform *xform_cipher;
3760         int status;
3761         size_t len;
3762
3763         if (n_tokens < 7 || strcmp(tokens[1], "cipher_algo") ||
3764                         strcmp(tokens[3], "cipher_key") ||
3765                         strcmp(tokens[5], "cipher_iv"))
3766                 return NULL;
3767
3768         xform_cipher = calloc(1, sizeof(*xform_cipher));
3769         if (xform_cipher == NULL)
3770                 return NULL;
3771
3772         xform_cipher->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
3773         xform_cipher->cipher.op = encrypt ? RTE_CRYPTO_CIPHER_OP_ENCRYPT :
3774                         RTE_CRYPTO_CIPHER_OP_DECRYPT;
3775
3776         /* cipher_algo */
3777         status = rte_cryptodev_get_cipher_algo_enum(
3778                         &xform_cipher->cipher.algo, tokens[2]);
3779         if (status < 0)
3780                 goto error_exit;
3781
3782         /* cipher_key */
3783         len = strlen(tokens[4]);
3784         xform_cipher->cipher.key.data = calloc(1, len / 2 + 1);
3785         if (xform_cipher->cipher.key.data == NULL)
3786                 goto error_exit;
3787
3788         status = parse_hex_string(tokens[4],
3789                         xform_cipher->cipher.key.data,
3790                         (uint32_t *)&len);
3791         if (status < 0)
3792                 goto error_exit;
3793
3794         xform_cipher->cipher.key.length = (uint16_t)len;
3795
3796         /* cipher_iv */
3797         len = strlen(tokens[6]);
3798
3799         p->cipher_auth.cipher_iv.val = calloc(1, len / 2 + 1);
3800         if (p->cipher_auth.cipher_iv.val == NULL)
3801                 goto error_exit;
3802
3803         status = parse_hex_string(tokens[6],
3804                         p->cipher_auth.cipher_iv.val,
3805                         (uint32_t *)&len);
3806         if (status < 0)
3807                 goto error_exit;
3808
3809         xform_cipher->cipher.iv.length = (uint16_t)len;
3810         xform_cipher->cipher.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
3811         p->cipher_auth.cipher_iv.length = (uint32_t)len;
3812         *used_n_tokens = 7;
3813
3814         return xform_cipher;
3815
3816 error_exit:
3817         if (xform_cipher->cipher.key.data)
3818                 free(xform_cipher->cipher.key.data);
3819
3820         if (p->cipher_auth.cipher_iv.val) {
3821                 free(p->cipher_auth.cipher_iv.val);
3822                 p->cipher_auth.cipher_iv.val = NULL;
3823         }
3824
3825         free(xform_cipher);
3826
3827         return NULL;
3828 }
3829
3830 static struct rte_crypto_sym_xform *
3831 parse_table_action_cipher_auth(struct rte_table_action_sym_crypto_params *p,
3832                 char **tokens, uint32_t n_tokens, uint32_t encrypt,
3833                 uint32_t *used_n_tokens)
3834 {
3835         struct rte_crypto_sym_xform *xform_cipher;
3836         struct rte_crypto_sym_xform *xform_auth;
3837         int status;
3838         size_t len;
3839
3840         if (n_tokens < 13 ||
3841                         strcmp(tokens[7], "auth_algo") ||
3842                         strcmp(tokens[9], "auth_key") ||
3843                         strcmp(tokens[11], "digest_size"))
3844                 return NULL;
3845
3846         xform_auth = calloc(1, sizeof(*xform_auth));
3847         if (xform_auth == NULL)
3848                 return NULL;
3849
3850         xform_auth->type = RTE_CRYPTO_SYM_XFORM_AUTH;
3851         xform_auth->auth.op = encrypt ? RTE_CRYPTO_AUTH_OP_GENERATE :
3852                         RTE_CRYPTO_AUTH_OP_VERIFY;
3853
3854         /* auth_algo */
3855         status = rte_cryptodev_get_auth_algo_enum(&xform_auth->auth.algo,
3856                         tokens[8]);
3857         if (status < 0)
3858                 goto error_exit;
3859
3860         /* auth_key */
3861         len = strlen(tokens[10]);
3862         xform_auth->auth.key.data = calloc(1, len / 2 + 1);
3863         if (xform_auth->auth.key.data == NULL)
3864                 goto error_exit;
3865
3866         status = parse_hex_string(tokens[10],
3867                         xform_auth->auth.key.data, (uint32_t *)&len);
3868         if (status < 0)
3869                 goto error_exit;
3870
3871         xform_auth->auth.key.length = (uint16_t)len;
3872
3873         if (strcmp(tokens[11], "digest_size"))
3874                 goto error_exit;
3875
3876         status = parser_read_uint16(&xform_auth->auth.digest_length,
3877                         tokens[12]);
3878         if (status < 0)
3879                 goto error_exit;
3880
3881         xform_cipher = parse_table_action_cipher(p, tokens, 7, encrypt,
3882                         used_n_tokens);
3883         if (xform_cipher == NULL)
3884                 goto error_exit;
3885
3886         *used_n_tokens += 6;
3887
3888         if (encrypt) {
3889                 xform_cipher->next = xform_auth;
3890                 return xform_cipher;
3891         } else {
3892                 xform_auth->next = xform_cipher;
3893                 return xform_auth;
3894         }
3895
3896 error_exit:
3897         if (xform_auth->auth.key.data)
3898                 free(xform_auth->auth.key.data);
3899         if (p->cipher_auth.auth_iv.val) {
3900                 free(p->cipher_auth.auth_iv.val);
3901                 p->cipher_auth.auth_iv.val = 0;
3902         }
3903
3904         free(xform_auth);
3905
3906         return NULL;
3907 }
3908
3909 static struct rte_crypto_sym_xform *
3910 parse_table_action_aead(struct rte_table_action_sym_crypto_params *p,
3911                 char **tokens, uint32_t n_tokens, uint32_t encrypt,
3912                 uint32_t *used_n_tokens)
3913 {
3914         struct rte_crypto_sym_xform *xform_aead;
3915         int status;
3916         size_t len;
3917
3918         if (n_tokens < 11 || strcmp(tokens[1], "aead_algo") ||
3919                         strcmp(tokens[3], "aead_key") ||
3920                         strcmp(tokens[5], "aead_iv") ||
3921                         strcmp(tokens[7], "aead_aad") ||
3922                         strcmp(tokens[9], "digest_size"))
3923                 return NULL;
3924
3925         xform_aead = calloc(1, sizeof(*xform_aead));
3926         if (xform_aead == NULL)
3927                 return NULL;
3928
3929         xform_aead->type = RTE_CRYPTO_SYM_XFORM_AEAD;
3930         xform_aead->aead.op = encrypt ? RTE_CRYPTO_AEAD_OP_ENCRYPT :
3931                         RTE_CRYPTO_AEAD_OP_DECRYPT;
3932
3933         /* aead_algo */
3934         status = rte_cryptodev_get_aead_algo_enum(&xform_aead->aead.algo,
3935                         tokens[2]);
3936         if (status < 0)
3937                 goto error_exit;
3938
3939         /* aead_key */
3940         len = strlen(tokens[4]);
3941         xform_aead->aead.key.data = calloc(1, len / 2 + 1);
3942         if (xform_aead->aead.key.data == NULL)
3943                 goto error_exit;
3944
3945         status = parse_hex_string(tokens[4], xform_aead->aead.key.data,
3946                         (uint32_t *)&len);
3947         if (status < 0)
3948                 goto error_exit;
3949
3950         xform_aead->aead.key.length = (uint16_t)len;
3951
3952         /* aead_iv */
3953         len = strlen(tokens[6]);
3954         p->aead.iv.val = calloc(1, len / 2 + 1);
3955         if (p->aead.iv.val == NULL)
3956                 goto error_exit;
3957
3958         status = parse_hex_string(tokens[6], p->aead.iv.val,
3959                         (uint32_t *)&len);
3960         if (status < 0)
3961                 goto error_exit;
3962
3963         xform_aead->aead.iv.length = (uint16_t)len;
3964         xform_aead->aead.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
3965         p->aead.iv.length = (uint32_t)len;
3966
3967         /* aead_aad */
3968         len = strlen(tokens[8]);
3969         p->aead.aad.val = calloc(1, len / 2 + 1);
3970         if (p->aead.aad.val == NULL)
3971                 goto error_exit;
3972
3973         status = parse_hex_string(tokens[8], p->aead.aad.val, (uint32_t *)&len);
3974         if (status < 0)
3975                 goto error_exit;
3976
3977         xform_aead->aead.aad_length = (uint16_t)len;
3978         p->aead.aad.length = (uint32_t)len;
3979
3980         /* digest_size */
3981         status = parser_read_uint16(&xform_aead->aead.digest_length,
3982                         tokens[10]);
3983         if (status < 0)
3984                 goto error_exit;
3985
3986         *used_n_tokens = 11;
3987
3988         return xform_aead;
3989
3990 error_exit:
3991         if (xform_aead->aead.key.data)
3992                 free(xform_aead->aead.key.data);
3993         if (p->aead.iv.val) {
3994                 free(p->aead.iv.val);
3995                 p->aead.iv.val = NULL;
3996         }
3997         if (p->aead.aad.val) {
3998                 free(p->aead.aad.val);
3999                 p->aead.aad.val = NULL;
4000         }
4001
4002         free(xform_aead);
4003
4004         return NULL;
4005 }
4006
4007
4008 static uint32_t
4009 parse_table_action_sym_crypto(char **tokens,
4010         uint32_t n_tokens,
4011         struct table_rule_action *a)
4012 {
4013         struct rte_table_action_sym_crypto_params *p = &a->sym_crypto;
4014         struct rte_crypto_sym_xform *xform = NULL;
4015         uint32_t used_n_tokens;
4016         uint32_t encrypt;
4017         int status;
4018
4019         if ((n_tokens < 12) ||
4020                 strcmp(tokens[0], "sym_crypto") ||
4021                 strcmp(tokens[2], "type"))
4022                 return 0;
4023
4024         memset(p, 0, sizeof(*p));
4025
4026         if (strcmp(tokens[1], "encrypt") == 0)
4027                 encrypt = 1;
4028         else
4029                 encrypt = 0;
4030
4031         status = parser_read_uint32(&p->data_offset, tokens[n_tokens - 1]);
4032         if (status < 0)
4033                 return 0;
4034
4035         if (strcmp(tokens[3], "cipher") == 0) {
4036                 tokens += 3;
4037                 n_tokens -= 3;
4038
4039                 xform = parse_table_action_cipher(p, tokens, n_tokens, encrypt,
4040                                 &used_n_tokens);
4041         } else if (strcmp(tokens[3], "cipher_auth") == 0) {
4042                 tokens += 3;
4043                 n_tokens -= 3;
4044
4045                 xform = parse_table_action_cipher_auth(p, tokens, n_tokens,
4046                                 encrypt, &used_n_tokens);
4047         } else if (strcmp(tokens[3], "aead") == 0) {
4048                 tokens += 3;
4049                 n_tokens -= 3;
4050
4051                 xform = parse_table_action_aead(p, tokens, n_tokens, encrypt,
4052                                 &used_n_tokens);
4053         }
4054
4055         if (xform == NULL)
4056                 return 0;
4057
4058         p->xform = xform;
4059
4060         if (strcmp(tokens[used_n_tokens], "data_offset")) {
4061                 parse_free_sym_crypto_param_data(p);
4062                 return 0;
4063         }
4064
4065         a->action_mask |= 1 << RTE_TABLE_ACTION_SYM_CRYPTO;
4066
4067         return used_n_tokens + 5;
4068 }
4069
4070 static uint32_t
4071 parse_table_action(char **tokens,
4072         uint32_t n_tokens,
4073         char *out,
4074         size_t out_size,
4075         struct table_rule_action *a)
4076 {
4077         uint32_t n_tokens0 = n_tokens;
4078
4079         memset(a, 0, sizeof(*a));
4080
4081         if ((n_tokens < 2) ||
4082                 strcmp(tokens[0], "action"))
4083                 return 0;
4084
4085         tokens++;
4086         n_tokens--;
4087
4088         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
4089                 uint32_t n;
4090
4091                 n = parse_table_action_fwd(tokens, n_tokens, a);
4092                 if (n == 0) {
4093                         snprintf(out, out_size, MSG_ARG_INVALID,
4094                                 "action fwd");
4095                         return 0;
4096                 }
4097
4098                 tokens += n;
4099                 n_tokens -= n;
4100         }
4101
4102         if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
4103                 uint32_t n;
4104
4105                 n = parse_table_action_balance(tokens, n_tokens, a);
4106                 if (n == 0) {
4107                         snprintf(out, out_size, MSG_ARG_INVALID,
4108                                 "action balance");
4109                         return 0;
4110                 }
4111
4112                 tokens += n;
4113                 n_tokens -= n;
4114         }
4115
4116         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
4117                 uint32_t n;
4118
4119                 n = parse_table_action_meter(tokens, n_tokens, a);
4120                 if (n == 0) {
4121                         snprintf(out, out_size, MSG_ARG_INVALID,
4122                                 "action meter");
4123                         return 0;
4124                 }
4125
4126                 tokens += n;
4127                 n_tokens -= n;
4128         }
4129
4130         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
4131                 uint32_t n;
4132
4133                 n = parse_table_action_tm(tokens, n_tokens, a);
4134                 if (n == 0) {
4135                         snprintf(out, out_size, MSG_ARG_INVALID,
4136                                 "action tm");
4137                         return 0;
4138                 }
4139
4140                 tokens += n;
4141                 n_tokens -= n;
4142         }
4143
4144         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
4145                 uint32_t n;
4146
4147                 n = parse_table_action_encap(tokens, n_tokens, a);
4148                 if (n == 0) {
4149                         snprintf(out, out_size, MSG_ARG_INVALID,
4150                                 "action encap");
4151                         return 0;
4152                 }
4153
4154                 tokens += n;
4155                 n_tokens -= n;
4156         }
4157
4158         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
4159                 uint32_t n;
4160
4161                 n = parse_table_action_nat(tokens, n_tokens, a);
4162                 if (n == 0) {
4163                         snprintf(out, out_size, MSG_ARG_INVALID,
4164                                 "action nat");
4165                         return 0;
4166                 }
4167
4168                 tokens += n;
4169                 n_tokens -= n;
4170         }
4171
4172         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
4173                 uint32_t n;
4174
4175                 n = parse_table_action_ttl(tokens, n_tokens, a);
4176                 if (n == 0) {
4177                         snprintf(out, out_size, MSG_ARG_INVALID,
4178                                 "action ttl");
4179                         return 0;
4180                 }
4181
4182                 tokens += n;
4183                 n_tokens -= n;
4184         }
4185
4186         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
4187                 uint32_t n;
4188
4189                 n = parse_table_action_stats(tokens, n_tokens, a);
4190                 if (n == 0) {
4191                         snprintf(out, out_size, MSG_ARG_INVALID,
4192                                 "action stats");
4193                         return 0;
4194                 }
4195
4196                 tokens += n;
4197                 n_tokens -= n;
4198         }
4199
4200         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
4201                 uint32_t n;
4202
4203                 n = parse_table_action_time(tokens, n_tokens, a);
4204                 if (n == 0) {
4205                         snprintf(out, out_size, MSG_ARG_INVALID,
4206                                 "action time");
4207                         return 0;
4208                 }
4209
4210                 tokens += n;
4211                 n_tokens -= n;
4212         }
4213
4214         if (n_tokens && (strcmp(tokens[0], "sym_crypto") == 0)) {
4215                 uint32_t n;
4216
4217                 n = parse_table_action_sym_crypto(tokens, n_tokens, a);
4218                 if (n == 0) {
4219                         snprintf(out, out_size, MSG_ARG_INVALID,
4220                                 "action sym_crypto");
4221                         return 0;
4222                 }
4223
4224                 tokens += n;
4225                 n_tokens -= n;
4226         }
4227
4228         if (n_tokens0 - n_tokens == 1) {
4229                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
4230                 return 0;
4231         }
4232
4233         return n_tokens0 - n_tokens;
4234 }
4235
4236
4237 static const char cmd_pipeline_table_rule_add_help[] =
4238 "pipeline <pipeline_name> table <table_id> rule add\n"
4239 "     match <match>\n"
4240 "     action <table_action>\n";
4241
4242 static void
4243 cmd_pipeline_table_rule_add(char **tokens,
4244         uint32_t n_tokens,
4245         char *out,
4246         size_t out_size)
4247 {
4248         struct table_rule_match m;
4249         struct table_rule_action a;
4250         char *pipeline_name;
4251         void *data;
4252         uint32_t table_id, t0, n_tokens_parsed;
4253         int status;
4254
4255         if (n_tokens < 8) {
4256                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4257                 return;
4258         }
4259
4260         pipeline_name = tokens[1];
4261
4262         if (strcmp(tokens[2], "table") != 0) {
4263                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4264                 return;
4265         }
4266
4267         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4268                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4269                 return;
4270         }
4271
4272         if (strcmp(tokens[4], "rule") != 0) {
4273                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4274                 return;
4275         }
4276
4277         if (strcmp(tokens[5], "add") != 0) {
4278                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4279                 return;
4280         }
4281
4282         t0 = 6;
4283
4284         /* match */
4285         n_tokens_parsed = parse_match(tokens + t0,
4286                 n_tokens - t0,
4287                 out,
4288                 out_size,
4289                 &m);
4290         if (n_tokens_parsed == 0)
4291                 return;
4292         t0 += n_tokens_parsed;
4293
4294         /* action */
4295         n_tokens_parsed = parse_table_action(tokens + t0,
4296                 n_tokens - t0,
4297                 out,
4298                 out_size,
4299                 &a);
4300         if (n_tokens_parsed == 0)
4301                 return;
4302         t0 += n_tokens_parsed;
4303
4304         if (t0 != n_tokens) {
4305                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
4306                 return;
4307         }
4308
4309         status = pipeline_table_rule_add(pipeline_name, table_id,
4310                 &m, &a, &data);
4311         if (status) {
4312                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4313                 return;
4314         }
4315
4316         if (a.action_mask & 1 << RTE_TABLE_ACTION_SYM_CRYPTO)
4317                 parse_free_sym_crypto_param_data(&a.sym_crypto);
4318 }
4319
4320
4321 static const char cmd_pipeline_table_rule_add_default_help[] =
4322 "pipeline <pipeline_name> table <table_id> rule add\n"
4323 "     match\n"
4324 "        default\n"
4325 "     action\n"
4326 "        fwd\n"
4327 "           drop\n"
4328 "           | port <port_id>\n"
4329 "           | meta\n"
4330 "           | table <table_id>\n";
4331
4332 static void
4333 cmd_pipeline_table_rule_add_default(char **tokens,
4334         uint32_t n_tokens,
4335         char *out,
4336         size_t out_size)
4337 {
4338         struct table_rule_action action;
4339         void *data;
4340         char *pipeline_name;
4341         uint32_t table_id;
4342         int status;
4343
4344         if ((n_tokens != 11) && (n_tokens != 12)) {
4345                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4346                 return;
4347         }
4348
4349         pipeline_name = tokens[1];
4350
4351         if (strcmp(tokens[2], "table") != 0) {
4352                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4353                 return;
4354         }
4355
4356         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4357                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4358                 return;
4359         }
4360
4361         if (strcmp(tokens[4], "rule") != 0) {
4362                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4363                 return;
4364         }
4365
4366         if (strcmp(tokens[5], "add") != 0) {
4367                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4368                 return;
4369         }
4370
4371         if (strcmp(tokens[6], "match") != 0) {
4372                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
4373                 return;
4374         }
4375
4376         if (strcmp(tokens[7], "default") != 0) {
4377                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
4378                 return;
4379         }
4380
4381         if (strcmp(tokens[8], "action") != 0) {
4382                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
4383                 return;
4384         }
4385
4386         if (strcmp(tokens[9], "fwd") != 0) {
4387                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
4388                 return;
4389         }
4390
4391         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
4392
4393         if (strcmp(tokens[10], "drop") == 0) {
4394                 if (n_tokens != 11) {
4395                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4396                         return;
4397                 }
4398
4399                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
4400         } else if (strcmp(tokens[10], "port") == 0) {
4401                 uint32_t id;
4402
4403                 if (n_tokens != 12) {
4404                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4405                         return;
4406                 }
4407
4408                 if (parser_read_uint32(&id, tokens[11]) != 0) {
4409                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
4410                         return;
4411                 }
4412
4413                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
4414                 action.fwd.id = id;
4415         } else if (strcmp(tokens[10], "meta") == 0) {
4416                 if (n_tokens != 11) {
4417                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4418                         return;
4419                 }
4420
4421                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
4422         } else if (strcmp(tokens[10], "table") == 0) {
4423                 uint32_t id;
4424
4425                 if (n_tokens != 12) {
4426                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4427                         return;
4428                 }
4429
4430                 if (parser_read_uint32(&id, tokens[11]) != 0) {
4431                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4432                         return;
4433                 }
4434
4435                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
4436                 action.fwd.id = id;
4437         } else {
4438                 snprintf(out, out_size, MSG_ARG_INVALID,
4439                         "drop or port or meta or table");
4440                 return;
4441         }
4442
4443         status = pipeline_table_rule_add_default(pipeline_name,
4444                 table_id,
4445                 &action,
4446                 &data);
4447         if (status) {
4448                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4449                 return;
4450         }
4451 }
4452
4453
4454 static const char cmd_pipeline_table_rule_add_bulk_help[] =
4455 "pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>\n"
4456 "\n"
4457 "  File <file_name>:\n"
4458 "  - line format: match <match> action <action>\n";
4459
4460 static int
4461 cli_rule_file_process(const char *file_name,
4462         size_t line_len_max,
4463         struct table_rule_match *m,
4464         struct table_rule_action *a,
4465         uint32_t *n_rules,
4466         uint32_t *line_number,
4467         char *out,
4468         size_t out_size);
4469
4470 static void
4471 cmd_pipeline_table_rule_add_bulk(char **tokens,
4472         uint32_t n_tokens,
4473         char *out,
4474         size_t out_size)
4475 {
4476         struct table_rule_match *match;
4477         struct table_rule_action *action;
4478         void **data;
4479         char *pipeline_name, *file_name;
4480         uint32_t table_id, n_rules, n_rules_parsed, line_number;
4481         int status;
4482
4483         if (n_tokens != 9) {
4484                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4485                 return;
4486         }
4487
4488         pipeline_name = tokens[1];
4489
4490         if (strcmp(tokens[2], "table") != 0) {
4491                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4492                 return;
4493         }
4494
4495         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4496                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4497                 return;
4498         }
4499
4500         if (strcmp(tokens[4], "rule") != 0) {
4501                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4502                 return;
4503         }
4504
4505         if (strcmp(tokens[5], "add") != 0) {
4506                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4507                 return;
4508         }
4509
4510         if (strcmp(tokens[6], "bulk") != 0) {
4511                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
4512                 return;
4513         }
4514
4515         file_name = tokens[7];
4516
4517         if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
4518                 (n_rules == 0)) {
4519                 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
4520                 return;
4521         }
4522
4523         /* Memory allocation. */
4524         match = calloc(n_rules, sizeof(struct table_rule_match));
4525         action = calloc(n_rules, sizeof(struct table_rule_action));
4526         data = calloc(n_rules, sizeof(void *));
4527         if ((match == NULL) || (action == NULL) || (data == NULL)) {
4528                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
4529                 free(data);
4530                 free(action);
4531                 free(match);
4532                 return;
4533         }
4534
4535         /* Load rule file */
4536         n_rules_parsed = n_rules;
4537         status = cli_rule_file_process(file_name,
4538                 1024,
4539                 match,
4540                 action,
4541                 &n_rules_parsed,
4542                 &line_number,
4543                 out,
4544                 out_size);
4545         if (status) {
4546                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4547                 free(data);
4548                 free(action);
4549                 free(match);
4550                 return;
4551         }
4552         if (n_rules_parsed != n_rules) {
4553                 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
4554                 free(data);
4555                 free(action);
4556                 free(match);
4557                 return;
4558         }
4559
4560         /* Rule bulk add */
4561         status = pipeline_table_rule_add_bulk(pipeline_name,
4562                 table_id,
4563                 match,
4564                 action,
4565                 data,
4566                 &n_rules);
4567         if (status) {
4568                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4569                 free(data);
4570                 free(action);
4571                 free(match);
4572                 return;
4573         }
4574
4575         /* Memory free */
4576         free(data);
4577         free(action);
4578         free(match);
4579 }
4580
4581
4582 static const char cmd_pipeline_table_rule_delete_help[] =
4583 "pipeline <pipeline_name> table <table_id> rule delete\n"
4584 "     match <match>\n";
4585
4586 static void
4587 cmd_pipeline_table_rule_delete(char **tokens,
4588         uint32_t n_tokens,
4589         char *out,
4590         size_t out_size)
4591 {
4592         struct table_rule_match m;
4593         char *pipeline_name;
4594         uint32_t table_id, n_tokens_parsed, t0;
4595         int status;
4596
4597         if (n_tokens < 8) {
4598                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4599                 return;
4600         }
4601
4602         pipeline_name = tokens[1];
4603
4604         if (strcmp(tokens[2], "table") != 0) {
4605                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4606                 return;
4607         }
4608
4609         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4610                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4611                 return;
4612         }
4613
4614         if (strcmp(tokens[4], "rule") != 0) {
4615                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4616                 return;
4617         }
4618
4619         if (strcmp(tokens[5], "delete") != 0) {
4620                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4621                 return;
4622         }
4623
4624         t0 = 6;
4625
4626         /* match */
4627         n_tokens_parsed = parse_match(tokens + t0,
4628                 n_tokens - t0,
4629                 out,
4630                 out_size,
4631                 &m);
4632         if (n_tokens_parsed == 0)
4633                 return;
4634         t0 += n_tokens_parsed;
4635
4636         if (n_tokens != t0) {
4637                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4638                 return;
4639         }
4640
4641         status = pipeline_table_rule_delete(pipeline_name,
4642                 table_id,
4643                 &m);
4644         if (status) {
4645                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4646                 return;
4647         }
4648 }
4649
4650
4651 static const char cmd_pipeline_table_rule_delete_default_help[] =
4652 "pipeline <pipeline_name> table <table_id> rule delete\n"
4653 "     match\n"
4654 "        default\n";
4655
4656 static void
4657 cmd_pipeline_table_rule_delete_default(char **tokens,
4658         uint32_t n_tokens,
4659         char *out,
4660         size_t out_size)
4661 {
4662         char *pipeline_name;
4663         uint32_t table_id;
4664         int status;
4665
4666         if (n_tokens != 8) {
4667                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4668                 return;
4669         }
4670
4671         pipeline_name = tokens[1];
4672
4673         if (strcmp(tokens[2], "table") != 0) {
4674                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4675                 return;
4676         }
4677
4678         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4679                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4680                 return;
4681         }
4682
4683         if (strcmp(tokens[4], "rule") != 0) {
4684                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4685                 return;
4686         }
4687
4688         if (strcmp(tokens[5], "delete") != 0) {
4689                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4690                 return;
4691         }
4692
4693         if (strcmp(tokens[6], "match") != 0) {
4694                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
4695                 return;
4696         }
4697
4698         if (strcmp(tokens[7], "default") != 0) {
4699                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
4700                 return;
4701         }
4702
4703         status = pipeline_table_rule_delete_default(pipeline_name,
4704                 table_id);
4705         if (status) {
4706                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4707                 return;
4708         }
4709 }
4710
4711
4712 static const char cmd_pipeline_table_rule_stats_read_help[] =
4713 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n";
4714
4715 static void
4716 cmd_pipeline_table_rule_stats_read(char **tokens,
4717         uint32_t n_tokens __rte_unused,
4718         char *out,
4719         size_t out_size)
4720 {
4721         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4722 }
4723
4724
4725 static const char cmd_pipeline_table_meter_profile_add_help[] =
4726 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n"
4727 "   add srtcm cir <cir> cbs <cbs> ebs <ebs>\n"
4728 "   | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
4729
4730 static void
4731 cmd_pipeline_table_meter_profile_add(char **tokens,
4732         uint32_t n_tokens,
4733         char *out,
4734         size_t out_size)
4735 {
4736         struct rte_table_action_meter_profile p;
4737         char *pipeline_name;
4738         uint32_t table_id, meter_profile_id;
4739         int status;
4740
4741         if (n_tokens < 9) {
4742                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4743                 return;
4744         }
4745
4746         pipeline_name = tokens[1];
4747
4748         if (strcmp(tokens[2], "table") != 0) {
4749                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4750                 return;
4751         }
4752
4753         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4754                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4755                 return;
4756         }
4757
4758         if (strcmp(tokens[4], "meter") != 0) {
4759                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4760                 return;
4761         }
4762
4763         if (strcmp(tokens[5], "profile") != 0) {
4764                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4765                 return;
4766         }
4767
4768         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4769                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4770                 return;
4771         }
4772
4773         if (strcmp(tokens[7], "add") != 0) {
4774                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4775                 return;
4776         }
4777
4778         if (strcmp(tokens[8], "srtcm") == 0) {
4779                 if (n_tokens != 15) {
4780                         snprintf(out, out_size, MSG_ARG_MISMATCH,
4781                                 tokens[0]);
4782                         return;
4783                 }
4784
4785                 p.alg = RTE_TABLE_ACTION_METER_SRTCM;
4786
4787                 if (strcmp(tokens[9], "cir") != 0) {
4788                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4789                         return;
4790                 }
4791
4792                 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
4793                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4794                         return;
4795                 }
4796
4797                 if (strcmp(tokens[11], "cbs") != 0) {
4798                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4799                         return;
4800                 }
4801
4802                 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
4803                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4804                         return;
4805                 }
4806
4807                 if (strcmp(tokens[13], "ebs") != 0) {
4808                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
4809                         return;
4810                 }
4811
4812                 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
4813                         snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
4814                         return;
4815                 }
4816         } else if (strcmp(tokens[8], "trtcm") == 0) {
4817                 if (n_tokens != 17) {
4818                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4819                         return;
4820                 }
4821
4822                 p.alg = RTE_TABLE_ACTION_METER_TRTCM;
4823
4824                 if (strcmp(tokens[9], "cir") != 0) {
4825                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4826                         return;
4827                 }
4828
4829                 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
4830                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4831                         return;
4832                 }
4833
4834                 if (strcmp(tokens[11], "pir") != 0) {
4835                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
4836                         return;
4837                 }
4838
4839                 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
4840                         snprintf(out, out_size, MSG_ARG_INVALID, "pir");
4841                         return;
4842                 }
4843                 if (strcmp(tokens[13], "cbs") != 0) {
4844                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4845                         return;
4846                 }
4847
4848                 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
4849                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4850                         return;
4851                 }
4852
4853                 if (strcmp(tokens[15], "pbs") != 0) {
4854                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
4855                         return;
4856                 }
4857
4858                 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
4859                         snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
4860                         return;
4861                 }
4862         } else {
4863                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4864                 return;
4865         }
4866
4867         status = pipeline_table_mtr_profile_add(pipeline_name,
4868                 table_id,
4869                 meter_profile_id,
4870                 &p);
4871         if (status) {
4872                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4873                 return;
4874         }
4875 }
4876
4877
4878 static const char cmd_pipeline_table_meter_profile_delete_help[] =
4879 "pipeline <pipeline_name> table <table_id>\n"
4880 "   meter profile <meter_profile_id> delete\n";
4881
4882 static void
4883 cmd_pipeline_table_meter_profile_delete(char **tokens,
4884         uint32_t n_tokens,
4885         char *out,
4886         size_t out_size)
4887 {
4888         char *pipeline_name;
4889         uint32_t table_id, meter_profile_id;
4890         int status;
4891
4892         if (n_tokens != 8) {
4893                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4894                 return;
4895         }
4896
4897         pipeline_name = tokens[1];
4898
4899         if (strcmp(tokens[2], "table") != 0) {
4900                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4901                 return;
4902         }
4903
4904         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4905                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4906                 return;
4907         }
4908
4909         if (strcmp(tokens[4], "meter") != 0) {
4910                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4911                 return;
4912         }
4913
4914         if (strcmp(tokens[5], "profile") != 0) {
4915                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4916                 return;
4917         }
4918
4919         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4920                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4921                 return;
4922         }
4923
4924         if (strcmp(tokens[7], "delete") != 0) {
4925                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4926                 return;
4927         }
4928
4929         status = pipeline_table_mtr_profile_delete(pipeline_name,
4930                 table_id,
4931                 meter_profile_id);
4932         if (status) {
4933                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4934                 return;
4935         }
4936 }
4937
4938
4939 static const char cmd_pipeline_table_rule_meter_read_help[] =
4940 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n";
4941
4942 static void
4943 cmd_pipeline_table_rule_meter_read(char **tokens,
4944         uint32_t n_tokens __rte_unused,
4945         char *out,
4946         size_t out_size)
4947 {
4948         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4949 }
4950
4951
4952 static const char cmd_pipeline_table_dscp_help[] =
4953 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n"
4954 "\n"
4955 " File <file_name>:\n"
4956 "   - exactly 64 lines\n"
4957 "   - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n";
4958
4959 static int
4960 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
4961         const char *file_name,
4962         uint32_t *line_number)
4963 {
4964         FILE *f = NULL;
4965         uint32_t dscp, l;
4966
4967         /* Check input arguments */
4968         if ((dscp_table == NULL) ||
4969                 (file_name == NULL) ||
4970                 (line_number == NULL)) {
4971                 if (line_number)
4972                         *line_number = 0;
4973                 return -EINVAL;
4974         }
4975
4976         /* Open input file */
4977         f = fopen(file_name, "r");
4978         if (f == NULL) {
4979                 *line_number = 0;
4980                 return -EINVAL;
4981         }
4982
4983         /* Read file */
4984         for (dscp = 0, l = 1; ; l++) {
4985                 char line[64];
4986                 char *tokens[3];
4987                 enum rte_meter_color color;
4988                 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
4989
4990                 if (fgets(line, sizeof(line), f) == NULL)
4991                         break;
4992
4993                 if (is_comment(line))
4994                         continue;
4995
4996                 if (parse_tokenize_string(line, tokens, &n_tokens)) {
4997                         *line_number = l;
4998                         fclose(f);
4999                         return -EINVAL;
5000                 }
5001
5002                 if (n_tokens == 0)
5003                         continue;
5004
5005                 if ((dscp >= RTE_DIM(dscp_table->entry)) ||
5006                         (n_tokens != RTE_DIM(tokens)) ||
5007                         parser_read_uint32(&tc_id, tokens[0]) ||
5008                         (tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
5009                         parser_read_uint32(&tc_queue_id, tokens[1]) ||
5010                         (tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
5011                         (strlen(tokens[2]) != 1)) {
5012                         *line_number = l;
5013                         fclose(f);
5014                         return -EINVAL;
5015                 }
5016
5017                 switch (tokens[2][0]) {
5018                 case 'g':
5019                 case 'G':
5020                         color = e_RTE_METER_GREEN;
5021                         break;
5022
5023                 case 'y':
5024                 case 'Y':
5025                         color = e_RTE_METER_YELLOW;
5026                         break;
5027
5028                 case 'r':
5029                 case 'R':
5030                         color = e_RTE_METER_RED;
5031                         break;
5032
5033                 default:
5034                         *line_number = l;
5035                         fclose(f);
5036                         return -EINVAL;
5037                 }
5038
5039                 dscp_table->entry[dscp].tc_id = tc_id;
5040                 dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
5041                 dscp_table->entry[dscp].color = color;
5042                 dscp++;
5043         }
5044
5045         /* Close file */
5046         fclose(f);
5047         return 0;
5048 }
5049
5050 static void
5051 cmd_pipeline_table_dscp(char **tokens,
5052         uint32_t n_tokens,
5053         char *out,
5054         size_t out_size)
5055 {
5056         struct rte_table_action_dscp_table dscp_table;
5057         char *pipeline_name, *file_name;
5058         uint32_t table_id, line_number;
5059         int status;
5060
5061         if (n_tokens != 6) {
5062                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5063                 return;
5064         }
5065
5066         pipeline_name = tokens[1];
5067
5068         if (strcmp(tokens[2], "table") != 0) {
5069                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5070                 return;
5071         }
5072
5073         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5074                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5075                 return;
5076         }
5077
5078         if (strcmp(tokens[4], "dscp") != 0) {
5079                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
5080                 return;
5081         }
5082
5083         file_name = tokens[5];
5084
5085         status = load_dscp_table(&dscp_table, file_name, &line_number);
5086         if (status) {
5087                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
5088                 return;
5089         }
5090
5091         status = pipeline_table_dscp_table_update(pipeline_name,
5092                 table_id,
5093                 UINT64_MAX,
5094                 &dscp_table);
5095         if (status) {
5096                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5097                 return;
5098         }
5099 }
5100
5101
5102 static const char cmd_pipeline_table_rule_ttl_read_help[] =
5103 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n";
5104
5105 static void
5106 cmd_pipeline_table_rule_ttl_read(char **tokens,
5107         uint32_t n_tokens __rte_unused,
5108         char *out,
5109         size_t out_size)
5110 {
5111         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
5112 }
5113
5114
5115 static const char cmd_thread_pipeline_enable_help[] =
5116 "thread <thread_id> pipeline <pipeline_name> enable\n";
5117
5118 static void
5119 cmd_thread_pipeline_enable(char **tokens,
5120         uint32_t n_tokens,
5121         char *out,
5122         size_t out_size)
5123 {
5124         char *pipeline_name;
5125         uint32_t thread_id;
5126         int status;
5127
5128         if (n_tokens != 5) {
5129                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5130                 return;
5131         }
5132
5133         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5134                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5135                 return;
5136         }
5137
5138         if (strcmp(tokens[2], "pipeline") != 0) {
5139                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5140                 return;
5141         }
5142
5143         pipeline_name = tokens[3];
5144
5145         if (strcmp(tokens[4], "enable") != 0) {
5146                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
5147                 return;
5148         }
5149
5150         status = thread_pipeline_enable(thread_id, pipeline_name);
5151         if (status) {
5152                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
5153                 return;
5154         }
5155 }
5156
5157
5158 static const char cmd_thread_pipeline_disable_help[] =
5159 "thread <thread_id> pipeline <pipeline_name> disable\n";
5160
5161 static void
5162 cmd_thread_pipeline_disable(char **tokens,
5163         uint32_t n_tokens,
5164         char *out,
5165         size_t out_size)
5166 {
5167         char *pipeline_name;
5168         uint32_t thread_id;
5169         int status;
5170
5171         if (n_tokens != 5) {
5172                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5173                 return;
5174         }
5175
5176         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5177                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5178                 return;
5179         }
5180
5181         if (strcmp(tokens[2], "pipeline") != 0) {
5182                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5183                 return;
5184         }
5185
5186         pipeline_name = tokens[3];
5187
5188         if (strcmp(tokens[4], "disable") != 0) {
5189                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
5190                 return;
5191         }
5192
5193         status = thread_pipeline_disable(thread_id, pipeline_name);
5194         if (status) {
5195                 snprintf(out, out_size, MSG_CMD_FAIL,
5196                         "thread pipeline disable");
5197                 return;
5198         }
5199 }
5200
5201 static void
5202 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
5203 {
5204         tokens++;
5205         n_tokens--;
5206
5207         if (n_tokens == 0) {
5208                 snprintf(out, out_size,
5209                         "Type 'help <command>' for details on each command.\n\n"
5210                         "List of commands:\n"
5211                         "\tmempool\n"
5212                         "\tlink\n"
5213                         "\tswq\n"
5214                         "\ttmgr subport profile\n"
5215                         "\ttmgr pipe profile\n"
5216                         "\ttmgr\n"
5217                         "\ttmgr subport\n"
5218                         "\ttmgr subport pipe\n"
5219                         "\ttap\n"
5220                         "\tkni\n"
5221                         "\tport in action profile\n"
5222                         "\ttable action profile\n"
5223                         "\tpipeline\n"
5224                         "\tpipeline port in\n"
5225                         "\tpipeline port out\n"
5226                         "\tpipeline table\n"
5227                         "\tpipeline port in table\n"
5228                         "\tpipeline port in stats\n"
5229                         "\tpipeline port in enable\n"
5230                         "\tpipeline port in disable\n"
5231                         "\tpipeline port out stats\n"
5232                         "\tpipeline table stats\n"
5233                         "\tpipeline table rule add\n"
5234                         "\tpipeline table rule add default\n"
5235                         "\tpipeline table rule add bulk\n"
5236                         "\tpipeline table rule delete\n"
5237                         "\tpipeline table rule delete default\n"
5238                         "\tpipeline table rule stats read\n"
5239                         "\tpipeline table meter profile add\n"
5240                         "\tpipeline table meter profile delete\n"
5241                         "\tpipeline table rule meter read\n"
5242                         "\tpipeline table dscp\n"
5243                         "\tpipeline table rule ttl read\n"
5244                         "\tthread pipeline enable\n"
5245                         "\tthread pipeline disable\n\n");
5246                 return;
5247         }
5248
5249         if (strcmp(tokens[0], "mempool") == 0) {
5250                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
5251                 return;
5252         }
5253
5254         if (strcmp(tokens[0], "link") == 0) {
5255                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
5256                 return;
5257         }
5258
5259         if (strcmp(tokens[0], "swq") == 0) {
5260                 snprintf(out, out_size, "\n%s\n", cmd_swq_help);
5261                 return;
5262         }
5263
5264         if (strcmp(tokens[0], "tmgr") == 0) {
5265                 if (n_tokens == 1) {
5266                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_help);
5267                         return;
5268                 }
5269
5270                 if ((n_tokens == 2) &&
5271                         (strcmp(tokens[1], "subport")) == 0) {
5272                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help);
5273                         return;
5274                 }
5275
5276                 if ((n_tokens == 3) &&
5277                         (strcmp(tokens[1], "subport") == 0) &&
5278                         (strcmp(tokens[2], "profile") == 0)) {
5279                         snprintf(out, out_size, "\n%s\n",
5280                                 cmd_tmgr_subport_profile_help);
5281                         return;
5282                 }
5283
5284                 if ((n_tokens == 3) &&
5285                         (strcmp(tokens[1], "subport") == 0) &&
5286                         (strcmp(tokens[2], "pipe") == 0)) {
5287                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help);
5288                         return;
5289                 }
5290
5291                 if ((n_tokens == 3) &&
5292                         (strcmp(tokens[1], "pipe") == 0) &&
5293                         (strcmp(tokens[2], "profile") == 0)) {
5294                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help);
5295                         return;
5296                 }
5297         }
5298
5299         if (strcmp(tokens[0], "tap") == 0) {
5300                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
5301                 return;
5302         }
5303
5304         if (strcmp(tokens[0], "kni") == 0) {
5305                 snprintf(out, out_size, "\n%s\n", cmd_kni_help);
5306                 return;
5307         }
5308
5309         if (strcmp(tokens[0], "cryptodev") == 0) {
5310                 snprintf(out, out_size, "\n%s\n", cmd_cryptodev_help);
5311                 return;
5312         }
5313
5314         if ((n_tokens == 4) &&
5315                 (strcmp(tokens[0], "port") == 0) &&
5316                 (strcmp(tokens[1], "in") == 0) &&
5317                 (strcmp(tokens[2], "action") == 0) &&
5318                 (strcmp(tokens[3], "profile") == 0)) {
5319                 snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help);
5320                 return;
5321         }
5322
5323         if ((n_tokens == 3) &&
5324                 (strcmp(tokens[0], "table") == 0) &&
5325                 (strcmp(tokens[1], "action") == 0) &&
5326                 (strcmp(tokens[2], "profile") == 0)) {
5327                 snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help);
5328                 return;
5329         }
5330
5331         if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) {
5332                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_help);
5333                 return;
5334         }
5335
5336         if ((strcmp(tokens[0], "pipeline") == 0) &&
5337                 (strcmp(tokens[1], "port") == 0)) {
5338                 if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) {
5339                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help);
5340                         return;
5341                 }
5342
5343                 if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) {
5344                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help);
5345                         return;
5346                 }
5347
5348                 if ((n_tokens == 4) &&
5349                         (strcmp(tokens[2], "in") == 0) &&
5350                         (strcmp(tokens[3], "table") == 0)) {
5351                         snprintf(out, out_size, "\n%s\n",
5352                                 cmd_pipeline_port_in_table_help);
5353                         return;
5354                 }
5355
5356                 if ((n_tokens == 4) &&
5357                         (strcmp(tokens[2], "in") == 0) &&
5358                         (strcmp(tokens[3], "stats") == 0)) {
5359                         snprintf(out, out_size, "\n%s\n",
5360                                 cmd_pipeline_port_in_stats_help);
5361                         return;
5362                 }
5363
5364                 if ((n_tokens == 4) &&
5365                         (strcmp(tokens[2], "in") == 0) &&
5366                         (strcmp(tokens[3], "enable") == 0)) {
5367                         snprintf(out, out_size, "\n%s\n",
5368                                 cmd_pipeline_port_in_enable_help);
5369                         return;
5370                 }
5371
5372                 if ((n_tokens == 4) &&
5373                         (strcmp(tokens[2], "in") == 0) &&
5374                         (strcmp(tokens[3], "disable") == 0)) {
5375                         snprintf(out, out_size, "\n%s\n",
5376                                 cmd_pipeline_port_in_disable_help);
5377                         return;
5378                 }
5379
5380                 if ((n_tokens == 4) &&
5381                         (strcmp(tokens[2], "out") == 0) &&
5382                         (strcmp(tokens[3], "stats") == 0)) {
5383                         snprintf(out, out_size, "\n%s\n",
5384                                 cmd_pipeline_port_out_stats_help);
5385                         return;
5386                 }
5387         }
5388
5389         if ((strcmp(tokens[0], "pipeline") == 0) &&
5390                 (strcmp(tokens[1], "table") == 0)) {
5391                 if (n_tokens == 2) {
5392                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help);
5393                         return;
5394                 }
5395
5396                 if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) {
5397                         snprintf(out, out_size, "\n%s\n",
5398                                 cmd_pipeline_table_stats_help);
5399                         return;
5400                 }
5401
5402                 if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) {
5403                         snprintf(out, out_size, "\n%s\n",
5404                                 cmd_pipeline_table_dscp_help);
5405                         return;
5406                 }
5407
5408                 if ((n_tokens == 4) &&
5409                         (strcmp(tokens[2], "rule") == 0) &&
5410                         (strcmp(tokens[3], "add") == 0)) {
5411                         snprintf(out, out_size, "\n%s\n",
5412                                 cmd_pipeline_table_rule_add_help);
5413                         return;
5414                 }
5415
5416                 if ((n_tokens == 5) &&
5417                         (strcmp(tokens[2], "rule") == 0) &&
5418                         (strcmp(tokens[3], "add") == 0) &&
5419                         (strcmp(tokens[4], "default") == 0)) {
5420                         snprintf(out, out_size, "\n%s\n",
5421                                 cmd_pipeline_table_rule_add_default_help);
5422                         return;
5423                 }
5424
5425                 if ((n_tokens == 5) &&
5426                         (strcmp(tokens[2], "rule") == 0) &&
5427                         (strcmp(tokens[3], "add") == 0) &&
5428                         (strcmp(tokens[4], "bulk") == 0)) {
5429                         snprintf(out, out_size, "\n%s\n",
5430                                 cmd_pipeline_table_rule_add_bulk_help);
5431                         return;
5432                 }
5433
5434                 if ((n_tokens == 4) &&
5435                         (strcmp(tokens[2], "rule") == 0) &&
5436                         (strcmp(tokens[3], "delete") == 0)) {
5437                         snprintf(out, out_size, "\n%s\n",
5438                                 cmd_pipeline_table_rule_delete_help);
5439                         return;
5440                 }
5441
5442                 if ((n_tokens == 5) &&
5443                         (strcmp(tokens[2], "rule") == 0) &&
5444                         (strcmp(tokens[3], "delete") == 0) &&
5445                         (strcmp(tokens[4], "default") == 0)) {
5446                         snprintf(out, out_size, "\n%s\n",
5447                                 cmd_pipeline_table_rule_delete_default_help);
5448                         return;
5449                 }
5450
5451                 if ((n_tokens == 5) &&
5452                         (strcmp(tokens[2], "rule") == 0) &&
5453                         (strcmp(tokens[3], "stats") == 0) &&
5454                         (strcmp(tokens[4], "read") == 0)) {
5455                         snprintf(out, out_size, "\n%s\n",
5456                                 cmd_pipeline_table_rule_stats_read_help);
5457                         return;
5458                 }
5459
5460                 if ((n_tokens == 5) &&
5461                         (strcmp(tokens[2], "meter") == 0) &&
5462                         (strcmp(tokens[3], "profile") == 0) &&
5463                         (strcmp(tokens[4], "add") == 0)) {
5464                         snprintf(out, out_size, "\n%s\n",
5465                                 cmd_pipeline_table_meter_profile_add_help);
5466                         return;
5467                 }
5468
5469                 if ((n_tokens == 5) &&
5470                         (strcmp(tokens[2], "meter") == 0) &&
5471                         (strcmp(tokens[3], "profile") == 0) &&
5472                         (strcmp(tokens[4], "delete") == 0)) {
5473                         snprintf(out, out_size, "\n%s\n",
5474                                 cmd_pipeline_table_meter_profile_delete_help);
5475                         return;
5476                 }
5477
5478                 if ((n_tokens == 5) &&
5479                         (strcmp(tokens[2], "rule") == 0) &&
5480                         (strcmp(tokens[3], "meter") == 0) &&
5481                         (strcmp(tokens[4], "read") == 0)) {
5482                         snprintf(out, out_size, "\n%s\n",
5483                                 cmd_pipeline_table_rule_meter_read_help);
5484                         return;
5485                 }
5486
5487                 if ((n_tokens == 5) &&
5488                         (strcmp(tokens[2], "rule") == 0) &&
5489                         (strcmp(tokens[3], "ttl") == 0) &&
5490                         (strcmp(tokens[4], "read") == 0)) {
5491                         snprintf(out, out_size, "\n%s\n",
5492                                 cmd_pipeline_table_rule_ttl_read_help);
5493                         return;
5494                 }
5495         }
5496
5497         if ((n_tokens == 3) &&
5498                 (strcmp(tokens[0], "thread") == 0) &&
5499                 (strcmp(tokens[1], "pipeline") == 0)) {
5500                 if (strcmp(tokens[2], "enable") == 0) {
5501                         snprintf(out, out_size, "\n%s\n",
5502                                 cmd_thread_pipeline_enable_help);
5503                         return;
5504                 }
5505
5506                 if (strcmp(tokens[2], "disable") == 0) {
5507                         snprintf(out, out_size, "\n%s\n",
5508                                 cmd_thread_pipeline_disable_help);
5509                         return;
5510                 }
5511         }
5512
5513         snprintf(out, out_size, "Invalid command\n");
5514 }
5515
5516 void
5517 cli_process(char *in, char *out, size_t out_size)
5518 {
5519         char *tokens[CMD_MAX_TOKENS];
5520         uint32_t n_tokens = RTE_DIM(tokens);
5521         int status;
5522
5523         if (is_comment(in))
5524                 return;
5525
5526         status = parse_tokenize_string(in, tokens, &n_tokens);
5527         if (status) {
5528                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
5529                 return;
5530         }
5531
5532         if (n_tokens == 0)
5533                 return;
5534
5535         if (strcmp(tokens[0], "help") == 0) {
5536                 cmd_help(tokens, n_tokens, out, out_size);
5537                 return;
5538         }
5539
5540         if (strcmp(tokens[0], "mempool") == 0) {
5541                 cmd_mempool(tokens, n_tokens, out, out_size);
5542                 return;
5543         }
5544
5545         if (strcmp(tokens[0], "link") == 0) {
5546                 if (strcmp(tokens[1], "show") == 0) {
5547                         cmd_link_show(tokens, n_tokens, out, out_size);
5548                         return;
5549                 }
5550
5551                 cmd_link(tokens, n_tokens, out, out_size);
5552                 return;
5553         }
5554
5555         if (strcmp(tokens[0], "swq") == 0) {
5556                 cmd_swq(tokens, n_tokens, out, out_size);
5557                 return;
5558         }
5559
5560         if (strcmp(tokens[0], "tmgr") == 0) {
5561                 if ((n_tokens >= 3) &&
5562                         (strcmp(tokens[1], "subport") == 0) &&
5563                         (strcmp(tokens[2], "profile") == 0)) {
5564                         cmd_tmgr_subport_profile(tokens, n_tokens,
5565                                 out, out_size);
5566                         return;
5567                 }
5568
5569                 if ((n_tokens >= 3) &&
5570                         (strcmp(tokens[1], "pipe") == 0) &&
5571                         (strcmp(tokens[2], "profile") == 0)) {
5572                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
5573                         return;
5574                 }
5575
5576                 if ((n_tokens >= 5) &&
5577                         (strcmp(tokens[2], "subport") == 0) &&
5578                         (strcmp(tokens[4], "profile") == 0)) {
5579                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
5580                         return;
5581                 }
5582
5583                 if ((n_tokens >= 5) &&
5584                         (strcmp(tokens[2], "subport") == 0) &&
5585                         (strcmp(tokens[4], "pipe") == 0)) {
5586                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
5587                         return;
5588                 }
5589
5590                 cmd_tmgr(tokens, n_tokens, out, out_size);
5591                 return;
5592         }
5593
5594         if (strcmp(tokens[0], "tap") == 0) {
5595                 cmd_tap(tokens, n_tokens, out, out_size);
5596                 return;
5597         }
5598
5599         if (strcmp(tokens[0], "kni") == 0) {
5600                 cmd_kni(tokens, n_tokens, out, out_size);
5601                 return;
5602         }
5603
5604         if (strcmp(tokens[0], "cryptodev") == 0) {
5605                 cmd_cryptodev(tokens, n_tokens, out, out_size);
5606                 return;
5607         }
5608
5609         if (strcmp(tokens[0], "port") == 0) {
5610                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
5611                 return;
5612         }
5613
5614         if (strcmp(tokens[0], "table") == 0) {
5615                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
5616                 return;
5617         }
5618
5619         if (strcmp(tokens[0], "pipeline") == 0) {
5620                 if ((n_tokens >= 3) &&
5621                         (strcmp(tokens[2], "period") == 0)) {
5622                         cmd_pipeline(tokens, n_tokens, out, out_size);
5623                         return;
5624                 }
5625
5626                 if ((n_tokens >= 5) &&
5627                         (strcmp(tokens[2], "port") == 0) &&
5628                         (strcmp(tokens[3], "in") == 0) &&
5629                         (strcmp(tokens[4], "bsz") == 0)) {
5630                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
5631                         return;
5632                 }
5633
5634                 if ((n_tokens >= 5) &&
5635                         (strcmp(tokens[2], "port") == 0) &&
5636                         (strcmp(tokens[3], "out") == 0) &&
5637                         (strcmp(tokens[4], "bsz") == 0)) {
5638                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
5639                         return;
5640                 }
5641
5642                 if ((n_tokens >= 4) &&
5643                         (strcmp(tokens[2], "table") == 0) &&
5644                         (strcmp(tokens[3], "match") == 0)) {
5645                         cmd_pipeline_table(tokens, n_tokens, out, out_size);
5646                         return;
5647                 }
5648
5649                 if ((n_tokens >= 6) &&
5650                         (strcmp(tokens[2], "port") == 0) &&
5651                         (strcmp(tokens[3], "in") == 0) &&
5652                         (strcmp(tokens[5], "table") == 0)) {
5653                         cmd_pipeline_port_in_table(tokens, n_tokens,
5654                                 out, out_size);
5655                         return;
5656                 }
5657
5658                 if ((n_tokens >= 6) &&
5659                         (strcmp(tokens[2], "port") == 0) &&
5660                         (strcmp(tokens[3], "in") == 0) &&
5661                         (strcmp(tokens[5], "stats") == 0)) {
5662                         cmd_pipeline_port_in_stats(tokens, n_tokens,
5663                                 out, out_size);
5664                         return;
5665                 }
5666
5667                 if ((n_tokens >= 6) &&
5668                         (strcmp(tokens[2], "port") == 0) &&
5669                         (strcmp(tokens[3], "in") == 0) &&
5670                         (strcmp(tokens[5], "enable") == 0)) {
5671                         cmd_pipeline_port_in_enable(tokens, n_tokens,
5672                                 out, out_size);
5673                         return;
5674                 }
5675
5676                 if ((n_tokens >= 6) &&
5677                         (strcmp(tokens[2], "port") == 0) &&
5678                         (strcmp(tokens[3], "in") == 0) &&
5679                         (strcmp(tokens[5], "disable") == 0)) {
5680                         cmd_pipeline_port_in_disable(tokens, n_tokens,
5681                                 out, out_size);
5682                         return;
5683                 }
5684
5685                 if ((n_tokens >= 6) &&
5686                         (strcmp(tokens[2], "port") == 0) &&
5687                         (strcmp(tokens[3], "out") == 0) &&
5688                         (strcmp(tokens[5], "stats") == 0)) {
5689                         cmd_pipeline_port_out_stats(tokens, n_tokens,
5690                                 out, out_size);
5691                         return;
5692                 }
5693
5694                 if ((n_tokens >= 5) &&
5695                         (strcmp(tokens[2], "table") == 0) &&
5696                         (strcmp(tokens[4], "stats") == 0)) {
5697                         cmd_pipeline_table_stats(tokens, n_tokens,
5698                                 out, out_size);
5699                         return;
5700                 }
5701
5702                 if ((n_tokens >= 7) &&
5703                         (strcmp(tokens[2], "table") == 0) &&
5704                         (strcmp(tokens[4], "rule") == 0) &&
5705                         (strcmp(tokens[5], "add") == 0) &&
5706                         (strcmp(tokens[6], "match") == 0)) {
5707                         if ((n_tokens >= 8) &&
5708                                 (strcmp(tokens[7], "default") == 0)) {
5709                                 cmd_pipeline_table_rule_add_default(tokens,
5710                                         n_tokens, out, out_size);
5711                                 return;
5712                         }
5713
5714                         cmd_pipeline_table_rule_add(tokens, n_tokens,
5715                                 out, out_size);
5716                         return;
5717                 }
5718
5719                 if ((n_tokens >= 7) &&
5720                         (strcmp(tokens[2], "table") == 0) &&
5721                         (strcmp(tokens[4], "rule") == 0) &&
5722                         (strcmp(tokens[5], "add") == 0) &&
5723                         (strcmp(tokens[6], "bulk") == 0)) {
5724                         cmd_pipeline_table_rule_add_bulk(tokens,
5725                                 n_tokens, out, out_size);
5726                         return;
5727                 }
5728
5729                 if ((n_tokens >= 7) &&
5730                         (strcmp(tokens[2], "table") == 0) &&
5731                         (strcmp(tokens[4], "rule") == 0) &&
5732                         (strcmp(tokens[5], "delete") == 0) &&
5733                         (strcmp(tokens[6], "match") == 0)) {
5734                         if ((n_tokens >= 8) &&
5735                                 (strcmp(tokens[7], "default") == 0)) {
5736                                 cmd_pipeline_table_rule_delete_default(tokens,
5737                                         n_tokens, out, out_size);
5738                                 return;
5739                                 }
5740
5741                         cmd_pipeline_table_rule_delete(tokens, n_tokens,
5742                                 out, out_size);
5743                         return;
5744                 }
5745
5746                 if ((n_tokens >= 7) &&
5747                         (strcmp(tokens[2], "table") == 0) &&
5748                         (strcmp(tokens[4], "rule") == 0) &&
5749                         (strcmp(tokens[5], "read") == 0) &&
5750                         (strcmp(tokens[6], "stats") == 0)) {
5751                         cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
5752                                 out, out_size);
5753                         return;
5754                 }
5755
5756                 if ((n_tokens >= 8) &&
5757                         (strcmp(tokens[2], "table") == 0) &&
5758                         (strcmp(tokens[4], "meter") == 0) &&
5759                         (strcmp(tokens[5], "profile") == 0) &&
5760                         (strcmp(tokens[7], "add") == 0)) {
5761                         cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
5762                                 out, out_size);
5763                         return;
5764                 }
5765
5766                 if ((n_tokens >= 8) &&
5767                         (strcmp(tokens[2], "table") == 0) &&
5768                         (strcmp(tokens[4], "meter") == 0) &&
5769                         (strcmp(tokens[5], "profile") == 0) &&
5770                         (strcmp(tokens[7], "delete") == 0)) {
5771                         cmd_pipeline_table_meter_profile_delete(tokens,
5772                                 n_tokens, out, out_size);
5773                         return;
5774                 }
5775
5776                 if ((n_tokens >= 7) &&
5777                         (strcmp(tokens[2], "table") == 0) &&
5778                         (strcmp(tokens[4], "rule") == 0) &&
5779                         (strcmp(tokens[5], "read") == 0) &&
5780                         (strcmp(tokens[6], "meter") == 0)) {
5781                         cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
5782                                 out, out_size);
5783                         return;
5784                 }
5785
5786                 if ((n_tokens >= 5) &&
5787                         (strcmp(tokens[2], "table") == 0) &&
5788                         (strcmp(tokens[4], "dscp") == 0)) {
5789                         cmd_pipeline_table_dscp(tokens, n_tokens,
5790                                 out, out_size);
5791                         return;
5792                 }
5793
5794                 if ((n_tokens >= 7) &&
5795                         (strcmp(tokens[2], "table") == 0) &&
5796                         (strcmp(tokens[4], "rule") == 0) &&
5797                         (strcmp(tokens[5], "read") == 0) &&
5798                         (strcmp(tokens[6], "ttl") == 0)) {
5799                         cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
5800                                 out, out_size);
5801                         return;
5802                 }
5803         }
5804
5805         if (strcmp(tokens[0], "thread") == 0) {
5806                 if ((n_tokens >= 5) &&
5807                         (strcmp(tokens[4], "enable") == 0)) {
5808                         cmd_thread_pipeline_enable(tokens, n_tokens,
5809                                 out, out_size);
5810                         return;
5811                 }
5812
5813                 if ((n_tokens >= 5) &&
5814                         (strcmp(tokens[4], "disable") == 0)) {
5815                         cmd_thread_pipeline_disable(tokens, n_tokens,
5816                                 out, out_size);
5817                         return;
5818                 }
5819         }
5820
5821         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
5822 }
5823
5824 int
5825 cli_script_process(const char *file_name,
5826         size_t msg_in_len_max,
5827         size_t msg_out_len_max)
5828 {
5829         char *msg_in = NULL, *msg_out = NULL;
5830         FILE *f = NULL;
5831
5832         /* Check input arguments */
5833         if ((file_name == NULL) ||
5834                 (strlen(file_name) == 0) ||
5835                 (msg_in_len_max == 0) ||
5836                 (msg_out_len_max == 0))
5837                 return -EINVAL;
5838
5839         msg_in = malloc(msg_in_len_max + 1);
5840         msg_out = malloc(msg_out_len_max + 1);
5841         if ((msg_in == NULL) ||
5842                 (msg_out == NULL)) {
5843                 free(msg_out);
5844                 free(msg_in);
5845                 return -ENOMEM;
5846         }
5847
5848         /* Open input file */
5849         f = fopen(file_name, "r");
5850         if (f == NULL) {
5851                 free(msg_out);
5852                 free(msg_in);
5853                 return -EIO;
5854         }
5855
5856         /* Read file */
5857         for ( ; ; ) {
5858                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
5859                         break;
5860
5861                 printf("%s", msg_in);
5862                 msg_out[0] = 0;
5863
5864                 cli_process(msg_in,
5865                         msg_out,
5866                         msg_out_len_max);
5867
5868                 if (strlen(msg_out))
5869                         printf("%s", msg_out);
5870         }
5871
5872         /* Close file */
5873         fclose(f);
5874         free(msg_out);
5875         free(msg_in);
5876         return 0;
5877 }
5878
5879 static int
5880 cli_rule_file_process(const char *file_name,
5881         size_t line_len_max,
5882         struct table_rule_match *m,
5883         struct table_rule_action *a,
5884         uint32_t *n_rules,
5885         uint32_t *line_number,
5886         char *out,
5887         size_t out_size)
5888 {
5889         FILE *f = NULL;
5890         char *line = NULL;
5891         uint32_t rule_id, line_id;
5892         int status = 0;
5893
5894         /* Check input arguments */
5895         if ((file_name == NULL) ||
5896                 (strlen(file_name) == 0) ||
5897                 (line_len_max == 0)) {
5898                 *line_number = 0;
5899                 return -EINVAL;
5900         }
5901
5902         /* Memory allocation */
5903         line = malloc(line_len_max + 1);
5904         if (line == NULL) {
5905                 *line_number = 0;
5906                 return -ENOMEM;
5907         }
5908
5909         /* Open file */
5910         f = fopen(file_name, "r");
5911         if (f == NULL) {
5912                 *line_number = 0;
5913                 free(line);
5914                 return -EIO;
5915         }
5916
5917         /* Read file */
5918         for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
5919                 char *tokens[CMD_MAX_TOKENS];
5920                 uint32_t n_tokens, n_tokens_parsed, t0;
5921
5922                 /* Read next line from file. */
5923                 if (fgets(line, line_len_max + 1, f) == NULL)
5924                         break;
5925
5926                 /* Comment. */
5927                 if (is_comment(line))
5928                         continue;
5929
5930                 /* Parse line. */
5931                 n_tokens = RTE_DIM(tokens);
5932                 status = parse_tokenize_string(line, tokens, &n_tokens);
5933                 if (status) {
5934                         status = -EINVAL;
5935                         break;
5936                 }
5937
5938                 /* Empty line. */
5939                 if (n_tokens == 0)
5940                         continue;
5941                 t0 = 0;
5942
5943                 /* Rule match. */
5944                 n_tokens_parsed = parse_match(tokens + t0,
5945                         n_tokens - t0,
5946                         out,
5947                         out_size,
5948                         &m[rule_id]);
5949                 if (n_tokens_parsed == 0) {
5950                         status = -EINVAL;
5951                         break;
5952                 }
5953                 t0 += n_tokens_parsed;
5954
5955                 /* Rule action. */
5956                 n_tokens_parsed = parse_table_action(tokens + t0,
5957                         n_tokens - t0,
5958                         out,
5959                         out_size,
5960                         &a[rule_id]);
5961                 if (n_tokens_parsed == 0) {
5962                         status = -EINVAL;
5963                         break;
5964                 }
5965                 t0 += n_tokens_parsed;
5966
5967                 /* Line completed. */
5968                 if (t0 < n_tokens) {
5969                         status = -EINVAL;
5970                         break;
5971                 }
5972
5973                 /* Increment rule count */
5974                 rule_id++;
5975         }
5976
5977         /* Close file */
5978         fclose(f);
5979
5980         /* Memory free */
5981         free(line);
5982
5983         *n_rules = rule_id;
5984         *line_number = line_id;
5985         return status;
5986 }