01c37691f4d28a3534a24d6dc007e8453122b1bc
[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 #include "kni.h"
16 #include "link.h"
17 #include "mempool.h"
18 #include "parser.h"
19 #include "pipeline.h"
20 #include "swq.h"
21 #include "tap.h"
22 #include "thread.h"
23 #include "tmgr.h"
24
25 #ifndef CMD_MAX_TOKENS
26 #define CMD_MAX_TOKENS     256
27 #endif
28
29 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
30 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
31 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
32 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
33 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
34 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
35 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
36 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
37 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
38 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
39 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
40
41 static int
42 is_comment(char *in)
43 {
44         if ((strlen(in) && index("!#%;", in[0])) ||
45                 (strncmp(in, "//", 2) == 0) ||
46                 (strncmp(in, "--", 2) == 0))
47                 return 1;
48
49         return 0;
50 }
51
52 static const char cmd_mempool_help[] =
53 "mempool <mempool_name>\n"
54 "   buffer <buffer_size>\n"
55 "   pool <pool_size>\n"
56 "   cache <cache_size>\n"
57 "   cpu <cpu_id>\n";
58
59 static void
60 cmd_mempool(char **tokens,
61         uint32_t n_tokens,
62         char *out,
63         size_t out_size)
64 {
65         struct mempool_params p;
66         char *name;
67         struct mempool *mempool;
68
69         if (n_tokens != 10) {
70                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
71                 return;
72         }
73
74         name = tokens[1];
75
76         if (strcmp(tokens[2], "buffer") != 0) {
77                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
78                 return;
79         }
80
81         if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
82                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
83                 return;
84         }
85
86         if (strcmp(tokens[4], "pool") != 0) {
87                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
88                 return;
89         }
90
91         if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
92                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
93                 return;
94         }
95
96         if (strcmp(tokens[6], "cache") != 0) {
97                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
98                 return;
99         }
100
101         if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
102                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
103                 return;
104         }
105
106         if (strcmp(tokens[8], "cpu") != 0) {
107                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
108                 return;
109         }
110
111         if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
112                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
113                 return;
114         }
115
116         mempool = mempool_create(name, &p);
117         if (mempool == NULL) {
118                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
119                 return;
120         }
121 }
122
123 static const char cmd_link_help[] =
124 "link <link_name>\n"
125 "   dev <device_name> | port <port_id>\n"
126 "   rxq <n_queues> <queue_size> <mempool_name>\n"
127 "   txq <n_queues> <queue_size>\n"
128 "   promiscuous on | off\n"
129 "   [rss <qid_0> ... <qid_n>]\n";
130
131 static void
132 cmd_link(char **tokens,
133         uint32_t n_tokens,
134         char *out,
135         size_t out_size)
136 {
137         struct link_params p;
138         struct link_params_rss rss;
139         struct link *link;
140         char *name;
141
142         memset(&p, 0, sizeof(p));
143
144         if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
145                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
146                 return;
147         }
148         name = tokens[1];
149
150         if (strcmp(tokens[2], "dev") == 0)
151                 p.dev_name = tokens[3];
152         else if (strcmp(tokens[2], "port") == 0) {
153                 p.dev_name = NULL;
154
155                 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
156                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
157                         return;
158                 }
159         } else {
160                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
161                 return;
162         }
163
164         if (strcmp(tokens[4], "rxq") != 0) {
165                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
166                 return;
167         }
168
169         if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
170                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
171                 return;
172         }
173         if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
174                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
175                 return;
176         }
177
178         p.rx.mempool_name = tokens[7];
179
180         if (strcmp(tokens[8], "txq") != 0) {
181                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
182                 return;
183         }
184
185         if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
186                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
187                 return;
188         }
189
190         if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
191                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
192                 return;
193         }
194
195         if (strcmp(tokens[11], "promiscuous") != 0) {
196                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
197                 return;
198         }
199
200         if (strcmp(tokens[12], "on") == 0)
201                 p.promiscuous = 1;
202         else if (strcmp(tokens[12], "off") == 0)
203                 p.promiscuous = 0;
204         else {
205                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
206                 return;
207         }
208
209         /* RSS */
210         p.rx.rss = NULL;
211         if (n_tokens > 13) {
212                 uint32_t queue_id, i;
213
214                 if (strcmp(tokens[13], "rss") != 0) {
215                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
216                         return;
217                 }
218
219                 p.rx.rss = &rss;
220
221                 rss.n_queues = 0;
222                 for (i = 14; i < n_tokens; i++) {
223                         if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
224                                 snprintf(out, out_size, MSG_ARG_INVALID,
225                                         "queue_id");
226                                 return;
227                         }
228
229                         rss.queue_id[rss.n_queues] = queue_id;
230                         rss.n_queues++;
231                 }
232         }
233
234         link = link_create(name, &p);
235         if (link == NULL) {
236                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
237                 return;
238         }
239 }
240
241 /* Print the link stats and info */
242 static void
243 print_link_info(struct link *link, char *out, size_t out_size)
244 {
245         struct rte_eth_stats stats;
246         struct ether_addr mac_addr;
247         struct rte_eth_link eth_link;
248         uint16_t mtu;
249
250         memset(&stats, 0, sizeof(stats));
251         rte_eth_stats_get(link->port_id, &stats);
252
253         rte_eth_macaddr_get(link->port_id, &mac_addr);
254         rte_eth_link_get(link->port_id, &eth_link);
255         rte_eth_dev_get_mtu(link->port_id, &mtu);
256
257         snprintf(out, out_size,
258                 "\n"
259                 "%s: flags=<%s> mtu %u\n"
260                 "\tether %02X:%02X:%02X:%02X:%02X:%02X rxqueues %u txqueues %u\n"
261                 "\tport# %u  speed %u Mbps\n"
262                 "\tRX packets %" PRIu64"  bytes %" PRIu64"\n"
263                 "\tRX errors %" PRIu64"  missed %" PRIu64"  no-mbuf %" PRIu64"\n"
264                 "\tTX packets %" PRIu64"  bytes %" PRIu64"\n"
265                 "\tTX errors %" PRIu64"\n",
266                 link->name,
267                 eth_link.link_status == 0 ? "DOWN" : "UP",
268                 mtu,
269                 mac_addr.addr_bytes[0], mac_addr.addr_bytes[1],
270                 mac_addr.addr_bytes[2], mac_addr.addr_bytes[3],
271                 mac_addr.addr_bytes[4], mac_addr.addr_bytes[5],
272                 link->n_rxq,
273                 link->n_txq,
274                 link->port_id,
275                 eth_link.link_speed,
276                 stats.ipackets,
277                 stats.ibytes,
278                 stats.ierrors,
279                 stats.imissed,
280                 stats.rx_nombuf,
281                 stats.opackets,
282                 stats.obytes,
283                 stats.oerrors);
284 }
285
286 /*
287  * link show [<link_name>]
288  */
289 static void
290 cmd_link_show(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
291 {
292         struct link *link;
293         char *link_name;
294
295         if (n_tokens != 2 && n_tokens != 3) {
296                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
297                 return;
298         }
299
300         if (n_tokens == 2) {
301                 link = link_next(NULL);
302
303                 while (link != NULL) {
304                         out_size = out_size - strlen(out);
305                         out = &out[strlen(out)];
306
307                         print_link_info(link, out, out_size);
308                         link = link_next(link);
309                 }
310         } else {
311                 out_size = out_size - strlen(out);
312                 out = &out[strlen(out)];
313
314                 link_name = tokens[2];
315                 link = link_find(link_name);
316
317                 if (link == NULL) {
318                         snprintf(out, out_size, MSG_ARG_INVALID,
319                                         "Link does not exist");
320                         return;
321                 }
322                 print_link_info(link, out, out_size);
323         }
324 }
325
326 static const char cmd_swq_help[] =
327 "swq <swq_name>\n"
328 "   size <size>\n"
329 "   cpu <cpu_id>\n";
330
331 static void
332 cmd_swq(char **tokens,
333         uint32_t n_tokens,
334         char *out,
335         size_t out_size)
336 {
337         struct swq_params p;
338         char *name;
339         struct swq *swq;
340
341         if (n_tokens != 6) {
342                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
343                 return;
344         }
345
346         name = tokens[1];
347
348         if (strcmp(tokens[2], "size") != 0) {
349                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
350                 return;
351         }
352
353         if (parser_read_uint32(&p.size, tokens[3]) != 0) {
354                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
355                 return;
356         }
357
358         if (strcmp(tokens[4], "cpu") != 0) {
359                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
360                 return;
361         }
362
363         if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
364                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
365                 return;
366         }
367
368         swq = swq_create(name, &p);
369         if (swq == NULL) {
370                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
371                 return;
372         }
373 }
374
375 static const char cmd_tmgr_subport_profile_help[] =
376 "tmgr subport profile\n"
377 "   <tb_rate> <tb_size>\n"
378 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>\n"
379 "   <tc_period>\n";
380
381 static void
382 cmd_tmgr_subport_profile(char **tokens,
383         uint32_t n_tokens,
384         char *out,
385         size_t out_size)
386 {
387         struct rte_sched_subport_params p;
388         int status, i;
389
390         if (n_tokens != 10) {
391                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
392                 return;
393         }
394
395         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
396                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
397                 return;
398         }
399
400         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
401                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
402                 return;
403         }
404
405         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
406                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
407                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
408                         return;
409                 }
410
411         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
412                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
413                 return;
414         }
415
416         status = tmgr_subport_profile_add(&p);
417         if (status != 0) {
418                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
419                 return;
420         }
421 }
422
423 static const char cmd_tmgr_pipe_profile_help[] =
424 "tmgr pipe profile\n"
425 "   <tb_rate> <tb_size>\n"
426 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>\n"
427 "   <tc_period>\n"
428 "   <tc_ov_weight>\n"
429 "   <wrr_weight0..15>\n";
430
431 static void
432 cmd_tmgr_pipe_profile(char **tokens,
433         uint32_t n_tokens,
434         char *out,
435         size_t out_size)
436 {
437         struct rte_sched_pipe_params p;
438         int status, i;
439
440         if (n_tokens != 27) {
441                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
442                 return;
443         }
444
445         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
446                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
447                 return;
448         }
449
450         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
451                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
452                 return;
453         }
454
455         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
456                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
457                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
458                         return;
459                 }
460
461         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
462                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
463                 return;
464         }
465
466 #ifdef RTE_SCHED_SUBPORT_TC_OV
467         if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) {
468                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
469                 return;
470         }
471 #endif
472
473         for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
474                 if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
475                         snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
476                         return;
477                 }
478
479         status = tmgr_pipe_profile_add(&p);
480         if (status != 0) {
481                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
482                 return;
483         }
484 }
485
486 static const char cmd_tmgr_help[] =
487 "tmgr <tmgr_name>\n"
488 "   rate <rate>\n"
489 "   spp <n_subports_per_port>\n"
490 "   pps <n_pipes_per_subport>\n"
491 "   qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>\n"
492 "   fo <frame_overhead>\n"
493 "   mtu <mtu>\n"
494 "   cpu <cpu_id>\n";
495
496 static void
497 cmd_tmgr(char **tokens,
498         uint32_t n_tokens,
499         char *out,
500         size_t out_size)
501 {
502         struct tmgr_port_params p;
503         char *name;
504         struct tmgr_port *tmgr_port;
505         int i;
506
507         if (n_tokens != 19) {
508                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
509                 return;
510         }
511
512         name = tokens[1];
513
514         if (strcmp(tokens[2], "rate") != 0) {
515                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
516                 return;
517         }
518
519         if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
520                 snprintf(out, out_size, MSG_ARG_INVALID, "rate");
521                 return;
522         }
523
524         if (strcmp(tokens[4], "spp") != 0) {
525                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
526                 return;
527         }
528
529         if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
530                 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
531                 return;
532         }
533
534         if (strcmp(tokens[6], "pps") != 0) {
535                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
536                 return;
537         }
538
539         if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
540                 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
541                 return;
542         }
543
544         if (strcmp(tokens[8], "qsize") != 0) {
545                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
546                 return;
547         }
548
549         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
550                 if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
551                         snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
552                         return;
553                 }
554
555         if (strcmp(tokens[13], "fo") != 0) {
556                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
557                 return;
558         }
559
560         if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
561                 snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
562                 return;
563         }
564
565         if (strcmp(tokens[15], "mtu") != 0) {
566                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
567                 return;
568         }
569
570         if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
571                 snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
572                 return;
573         }
574
575         if (strcmp(tokens[17], "cpu") != 0) {
576                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
577                 return;
578         }
579
580         if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
581                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
582                 return;
583         }
584
585         tmgr_port = tmgr_port_create(name, &p);
586         if (tmgr_port == NULL) {
587                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
588                 return;
589         }
590 }
591
592 static const char cmd_tmgr_subport_help[] =
593 "tmgr <tmgr_name> subport <subport_id>\n"
594 "   profile <subport_profile_id>\n";
595
596 static void
597 cmd_tmgr_subport(char **tokens,
598         uint32_t n_tokens,
599         char *out,
600         size_t out_size)
601 {
602         uint32_t subport_id, subport_profile_id;
603         int status;
604         char *name;
605
606         if (n_tokens != 6) {
607                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
608                 return;
609         }
610
611         name = tokens[1];
612
613         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
614                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
615                 return;
616         }
617
618         if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
619                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
620                 return;
621         }
622
623         status = tmgr_subport_config(name, subport_id, subport_profile_id);
624         if (status) {
625                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
626                 return;
627         }
628 }
629
630
631 static const char cmd_tmgr_subport_pipe_help[] =
632 "tmgr <tmgr_name> subport <subport_id> pipe\n"
633 "   from <pipe_id_first> to <pipe_id_last>\n"
634 "   profile <pipe_profile_id>\n";
635
636 static void
637 cmd_tmgr_subport_pipe(char **tokens,
638         uint32_t n_tokens,
639         char *out,
640         size_t out_size)
641 {
642         uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
643         int status;
644         char *name;
645
646         if (n_tokens != 11) {
647                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
648                 return;
649         }
650
651         name = tokens[1];
652
653         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
654                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
655                 return;
656         }
657
658         if (strcmp(tokens[4], "pipe") != 0) {
659                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
660                 return;
661         }
662
663         if (strcmp(tokens[5], "from") != 0) {
664                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
665                 return;
666         }
667
668         if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
669                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
670                 return;
671         }
672
673         if (strcmp(tokens[7], "to") != 0) {
674                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
675                 return;
676         }
677
678         if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
679                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
680                 return;
681         }
682
683         if (strcmp(tokens[9], "profile") != 0) {
684                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
685                 return;
686         }
687
688         if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
689                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
690                 return;
691         }
692
693         status = tmgr_pipe_config(name, subport_id, pipe_id_first,
694                         pipe_id_last, pipe_profile_id);
695         if (status) {
696                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
697                 return;
698         }
699 }
700
701
702 static const char cmd_tap_help[] =
703 "tap <tap_name>\n";
704
705 static void
706 cmd_tap(char **tokens,
707         uint32_t n_tokens,
708         char *out,
709         size_t out_size)
710 {
711         char *name;
712         struct tap *tap;
713
714         if (n_tokens != 2) {
715                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
716                 return;
717         }
718
719         name = tokens[1];
720
721         tap = tap_create(name);
722         if (tap == NULL) {
723                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
724                 return;
725         }
726 }
727
728 static const char cmd_kni_help[] =
729 "kni <kni_name>\n"
730 "   link <link_name>\n"
731 "   mempool <mempool_name>\n"
732 "   [thread <thread_id>]\n";
733
734 static void
735 cmd_kni(char **tokens,
736         uint32_t n_tokens,
737         char *out,
738         size_t out_size)
739 {
740         struct kni_params p;
741         char *name;
742         struct kni *kni;
743
744         memset(&p, 0, sizeof(p));
745         if ((n_tokens != 6) && (n_tokens != 8)) {
746                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
747                 return;
748         }
749
750         name = tokens[1];
751
752         if (strcmp(tokens[2], "link") != 0) {
753                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
754                 return;
755         }
756
757         p.link_name = tokens[3];
758
759         if (strcmp(tokens[4], "mempool") != 0) {
760                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
761                 return;
762         }
763
764         p.mempool_name = tokens[5];
765
766         if (n_tokens == 8) {
767                 if (strcmp(tokens[6], "thread") != 0) {
768                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
769                         return;
770                 }
771
772                 if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
773                         snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
774                         return;
775                 }
776
777                 p.force_bind = 1;
778         } else
779                 p.force_bind = 0;
780
781         kni = kni_create(name, &p);
782         if (kni == NULL) {
783                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
784                 return;
785         }
786 }
787
788
789 static const char cmd_port_in_action_profile_help[] =
790 "port in action profile <profile_name>\n"
791 "   [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]\n"
792 "   [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]\n";
793
794 static void
795 cmd_port_in_action_profile(char **tokens,
796         uint32_t n_tokens,
797         char *out,
798         size_t out_size)
799 {
800         struct port_in_action_profile_params p;
801         struct port_in_action_profile *ap;
802         char *name;
803         uint32_t t0;
804
805         memset(&p, 0, sizeof(p));
806
807         if (n_tokens < 5) {
808                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
809                 return;
810         }
811
812         if (strcmp(tokens[1], "in") != 0) {
813                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
814                 return;
815         }
816
817         if (strcmp(tokens[2], "action") != 0) {
818                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
819                 return;
820         }
821
822         if (strcmp(tokens[3], "profile") != 0) {
823                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
824                 return;
825         }
826
827         name = tokens[4];
828
829         t0 = 5;
830
831         if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) {
832                 uint32_t size;
833
834                 if (n_tokens < t0 + 10) {
835                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
836                         return;
837                 }
838
839                 if (strcmp(tokens[t0 + 1], "match") == 0)
840                         p.fltr.filter_on_match = 1;
841                 else if (strcmp(tokens[t0 + 1], "mismatch") == 0)
842                         p.fltr.filter_on_match = 0;
843                 else {
844                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
845                         return;
846                 }
847
848                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
849                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
850                         return;
851                 }
852
853                 if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) {
854                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
855                         return;
856                 }
857
858                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
859                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
860                         return;
861                 }
862
863                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
864                 if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) ||
865                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
866                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
867                         return;
868                 }
869
870                 if (strcmp(tokens[t0 + 6], "key") != 0) {
871                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
872                         return;
873                 }
874
875                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
876                 if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) ||
877                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
878                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
879                         return;
880                 }
881
882                 if (strcmp(tokens[t0 + 8], "port") != 0) {
883                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
884                         return;
885                 }
886
887                 if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) {
888                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
889                         return;
890                 }
891
892                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
893                 t0 += 10;
894         } /* filter */
895
896         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
897                 uint32_t i;
898
899                 if (n_tokens < t0 + 22) {
900                         snprintf(out, out_size, MSG_ARG_MISMATCH,
901                                 "port in action profile balance");
902                         return;
903                 }
904
905                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
906                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
907                         return;
908                 }
909
910                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
911                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
912                         return;
913                 }
914
915                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
916                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
917                         return;
918                 }
919
920                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
921                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
922                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
923                         return;
924                 }
925
926                 if (strcmp(tokens[t0 + 5], "port") != 0) {
927                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
928                         return;
929                 }
930
931                 for (i = 0; i < 16; i++)
932                         if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) {
933                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
934                                 return;
935                         }
936
937                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
938                 t0 += 22;
939         } /* balance */
940
941         if (t0 < n_tokens) {
942                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
943                 return;
944         }
945
946         ap = port_in_action_profile_create(name, &p);
947         if (ap == NULL) {
948                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
949                 return;
950         }
951 }
952
953
954 static const char cmd_table_action_profile_help[] =
955 "table action profile <profile_name>\n"
956 "   ipv4 | ipv6\n"
957 "   offset <ip_offset>\n"
958 "   fwd\n"
959 "   [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]\n"
960 "   [meter srtcm | trtcm\n"
961 "       tc <n_tc>\n"
962 "       stats none | pkts | bytes | both]\n"
963 "   [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]\n"
964 "   [encap ether | vlan | qinq | mpls | pppoe |\n"
965 "       vxlan offset <ether_offset> ipv4 | ipv6 vlan on | off]\n"
966 "   [nat src | dst\n"
967 "       proto udp | tcp]\n"
968 "   [ttl drop | fwd\n"
969 "       stats none | pkts]\n"
970 "   [stats pkts | bytes | both]\n"
971 "   [time]\n";
972
973 static void
974 cmd_table_action_profile(char **tokens,
975         uint32_t n_tokens,
976         char *out,
977         size_t out_size)
978 {
979         struct table_action_profile_params p;
980         struct table_action_profile *ap;
981         char *name;
982         uint32_t t0;
983
984         memset(&p, 0, sizeof(p));
985
986         if (n_tokens < 8) {
987                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
988                 return;
989         }
990
991         if (strcmp(tokens[1], "action") != 0) {
992                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
993                 return;
994         }
995
996         if (strcmp(tokens[2], "profile") != 0) {
997                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
998                 return;
999         }
1000
1001         name = tokens[3];
1002
1003         if (strcmp(tokens[4], "ipv4") == 0)
1004                 p.common.ip_version = 1;
1005         else if (strcmp(tokens[4], "ipv6") == 0)
1006                 p.common.ip_version = 0;
1007         else {
1008                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
1009                 return;
1010         }
1011
1012         if (strcmp(tokens[5], "offset") != 0) {
1013                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1014                 return;
1015         }
1016
1017         if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
1018                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
1019                 return;
1020         }
1021
1022         if (strcmp(tokens[7], "fwd") != 0) {
1023                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
1024                 return;
1025         }
1026
1027         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
1028
1029         t0 = 8;
1030         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
1031                 if (n_tokens < t0 + 7) {
1032                         snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
1033                         return;
1034                 }
1035
1036                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1037                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1038                         return;
1039                 }
1040
1041                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
1042                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1043                         return;
1044                 }
1045
1046                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
1047                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1048                         return;
1049                 }
1050
1051                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
1052                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
1053                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1054                         return;
1055                 }
1056
1057                 if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
1058                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
1059                         return;
1060                 }
1061
1062                 if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) {
1063                         snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
1064                         return;
1065                 }
1066
1067                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
1068                 t0 += 7;
1069         } /* balance */
1070
1071         if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
1072                 if (n_tokens < t0 + 6) {
1073                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1074                                 "table action profile meter");
1075                         return;
1076                 }
1077
1078                 if (strcmp(tokens[t0 + 1], "srtcm") == 0)
1079                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
1080                 else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
1081                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
1082                 else {
1083                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1084                                 "srtcm or trtcm");
1085                         return;
1086                 }
1087
1088                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
1089                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
1090                         return;
1091                 }
1092
1093                 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
1094                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
1095                         return;
1096                 }
1097
1098                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
1099                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1100                         return;
1101                 }
1102
1103                 if (strcmp(tokens[t0 + 5], "none") == 0) {
1104                         p.mtr.n_packets_enabled = 0;
1105                         p.mtr.n_bytes_enabled = 0;
1106                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
1107                         p.mtr.n_packets_enabled = 1;
1108                         p.mtr.n_bytes_enabled = 0;
1109                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
1110                         p.mtr.n_packets_enabled = 0;
1111                         p.mtr.n_bytes_enabled = 1;
1112                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
1113                         p.mtr.n_packets_enabled = 1;
1114                         p.mtr.n_bytes_enabled = 1;
1115                 } else {
1116                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1117                                 "none or pkts or bytes or both");
1118                         return;
1119                 }
1120
1121                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
1122                 t0 += 6;
1123         } /* meter */
1124
1125         if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
1126                 if (n_tokens < t0 + 5) {
1127                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1128                                 "table action profile tm");
1129                         return;
1130                 }
1131
1132                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
1133                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
1134                         return;
1135                 }
1136
1137                 if (parser_read_uint32(&p.tm.n_subports_per_port,
1138                         tokens[t0 + 2]) != 0) {
1139                         snprintf(out, out_size, MSG_ARG_INVALID,
1140                                 "n_subports_per_port");
1141                         return;
1142                 }
1143
1144                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
1145                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1146                         return;
1147                 }
1148
1149                 if (parser_read_uint32(&p.tm.n_pipes_per_subport,
1150                         tokens[t0 + 4]) != 0) {
1151                         snprintf(out, out_size, MSG_ARG_INVALID,
1152                                 "n_pipes_per_subport");
1153                         return;
1154                 }
1155
1156                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1157                 t0 += 5;
1158         } /* tm */
1159
1160         if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
1161                 uint32_t n_extra_tokens = 0;
1162
1163                 if (n_tokens < t0 + 2) {
1164                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1165                                 "action profile encap");
1166                         return;
1167                 }
1168
1169                 if (strcmp(tokens[t0 + 1], "ether") == 0)
1170                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1171                 else if (strcmp(tokens[t0 + 1], "vlan") == 0)
1172                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1173                 else if (strcmp(tokens[t0 + 1], "qinq") == 0)
1174                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1175                 else if (strcmp(tokens[t0 + 1], "mpls") == 0)
1176                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1177                 else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
1178                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1179                 else if (strcmp(tokens[t0 + 1], "vxlan") == 0) {
1180                         if (n_tokens < t0 + 2 + 5) {
1181                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
1182                                         "action profile encap vxlan");
1183                                 return;
1184                         }
1185
1186                         if (strcmp(tokens[t0 + 2], "offset") != 0) {
1187                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1188                                         "vxlan: offset");
1189                                 return;
1190                         }
1191
1192                         if (parser_read_uint32(&p.encap.vxlan.data_offset,
1193                                 tokens[t0 + 2 + 1]) != 0) {
1194                                 snprintf(out, out_size, MSG_ARG_INVALID,
1195                                         "vxlan: ether_offset");
1196                                 return;
1197                         }
1198
1199                         if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0)
1200                                 p.encap.vxlan.ip_version = 1;
1201                         else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0)
1202                                 p.encap.vxlan.ip_version = 0;
1203                         else {
1204                                 snprintf(out, out_size, MSG_ARG_INVALID,
1205                                         "vxlan: ipv4 or ipv6");
1206                                 return;
1207                         }
1208
1209                         if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) {
1210                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1211                                         "vxlan: vlan");
1212                                 return;
1213                         }
1214
1215                         if (strcmp(tokens[t0 + 2 + 4], "on") == 0)
1216                                 p.encap.vxlan.vlan = 1;
1217                         else if (strcmp(tokens[t0 + 2 + 4], "off") == 0)
1218                                 p.encap.vxlan.vlan = 0;
1219                         else {
1220                                 snprintf(out, out_size, MSG_ARG_INVALID,
1221                                         "vxlan: on or off");
1222                                 return;
1223                         }
1224
1225                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN;
1226                         n_extra_tokens = 5;
1227                 } else {
1228                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1229                         return;
1230                 }
1231
1232                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1233                 t0 += 2 + n_extra_tokens;
1234         } /* encap */
1235
1236         if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
1237                 if (n_tokens < t0 + 4) {
1238                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1239                                 "table action profile nat");
1240                         return;
1241                 }
1242
1243                 if (strcmp(tokens[t0 + 1], "src") == 0)
1244                         p.nat.source_nat = 1;
1245                 else if (strcmp(tokens[t0 + 1], "dst") == 0)
1246                         p.nat.source_nat = 0;
1247                 else {
1248                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1249                                 "src or dst");
1250                         return;
1251                 }
1252
1253                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
1254                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1255                         return;
1256                 }
1257
1258                 if (strcmp(tokens[t0 + 3], "tcp") == 0)
1259                         p.nat.proto = 0x06;
1260                 else if (strcmp(tokens[t0 + 3], "udp") == 0)
1261                         p.nat.proto = 0x11;
1262                 else {
1263                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1264                                 "tcp or udp");
1265                         return;
1266                 }
1267
1268                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1269                 t0 += 4;
1270         } /* nat */
1271
1272         if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
1273                 if (n_tokens < t0 + 4) {
1274                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1275                                 "table action profile ttl");
1276                         return;
1277                 }
1278
1279                 if (strcmp(tokens[t0 + 1], "drop") == 0)
1280                         p.ttl.drop = 1;
1281                 else if (strcmp(tokens[t0 + 1], "fwd") == 0)
1282                         p.ttl.drop = 0;
1283                 else {
1284                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1285                                 "drop or fwd");
1286                         return;
1287                 }
1288
1289                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
1290                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1291                         return;
1292                 }
1293
1294                 if (strcmp(tokens[t0 + 3], "none") == 0)
1295                         p.ttl.n_packets_enabled = 0;
1296                 else if (strcmp(tokens[t0 + 3], "pkts") == 0)
1297                         p.ttl.n_packets_enabled = 1;
1298                 else {
1299                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1300                                 "none or pkts");
1301                         return;
1302                 }
1303
1304                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1305                 t0 += 4;
1306         } /* ttl */
1307
1308         if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
1309                 if (n_tokens < t0 + 2) {
1310                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1311                                 "table action profile stats");
1312                         return;
1313                 }
1314
1315                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1316                         p.stats.n_packets_enabled = 1;
1317                         p.stats.n_bytes_enabled = 0;
1318                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1319                         p.stats.n_packets_enabled = 0;
1320                         p.stats.n_bytes_enabled = 1;
1321                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
1322                         p.stats.n_packets_enabled = 1;
1323                         p.stats.n_bytes_enabled = 1;
1324                 } else {
1325                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1326                                 "pkts or bytes or both");
1327                         return;
1328                 }
1329
1330                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1331                 t0 += 2;
1332         } /* stats */
1333
1334         if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
1335                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1336                 t0 += 1;
1337         } /* time */
1338
1339         if (t0 < n_tokens) {
1340                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1341                 return;
1342         }
1343
1344         ap = table_action_profile_create(name, &p);
1345         if (ap == NULL) {
1346                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1347                 return;
1348         }
1349 }
1350
1351 static const char cmd_pipeline_help[] =
1352 "pipeline <pipeline_name>\n"
1353 "   period <timer_period_ms>\n"
1354 "   offset_port_id <offset_port_id>\n"
1355 "   cpu <cpu_id>\n";
1356
1357 static void
1358 cmd_pipeline(char **tokens,
1359         uint32_t n_tokens,
1360         char *out,
1361         size_t out_size)
1362 {
1363         struct pipeline_params p;
1364         char *name;
1365         struct pipeline *pipeline;
1366
1367         if (n_tokens != 8) {
1368                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1369                 return;
1370         }
1371
1372         name = tokens[1];
1373
1374         if (strcmp(tokens[2], "period") != 0) {
1375                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
1376                 return;
1377         }
1378
1379         if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
1380                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
1381                 return;
1382         }
1383
1384         if (strcmp(tokens[4], "offset_port_id") != 0) {
1385                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
1386                 return;
1387         }
1388
1389         if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
1390                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
1391                 return;
1392         }
1393
1394         if (strcmp(tokens[6], "cpu") != 0) {
1395                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
1396                 return;
1397         }
1398
1399         if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
1400                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
1401                 return;
1402         }
1403
1404         pipeline = pipeline_create(name, &p);
1405         if (pipeline == NULL) {
1406                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1407                 return;
1408         }
1409 }
1410
1411 static const char cmd_pipeline_port_in_help[] =
1412 "pipeline <pipeline_name> port in\n"
1413 "   bsz <burst_size>\n"
1414 "   link <link_name> rxq <queue_id>\n"
1415 "   | swq <swq_name>\n"
1416 "   | tmgr <tmgr_name>\n"
1417 "   | tap <tap_name> mempool <mempool_name> mtu <mtu>\n"
1418 "   | kni <kni_name>\n"
1419 "   | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>\n"
1420 "   [action <port_in_action_profile_name>]\n"
1421 "   [disabled]\n";
1422
1423 static void
1424 cmd_pipeline_port_in(char **tokens,
1425         uint32_t n_tokens,
1426         char *out,
1427         size_t out_size)
1428 {
1429         struct port_in_params p;
1430         char *pipeline_name;
1431         uint32_t t0;
1432         int enabled, status;
1433
1434         if (n_tokens < 7) {
1435                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1436                 return;
1437         }
1438
1439         pipeline_name = tokens[1];
1440
1441         if (strcmp(tokens[2], "port") != 0) {
1442                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1443                 return;
1444         }
1445
1446         if (strcmp(tokens[3], "in") != 0) {
1447                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1448                 return;
1449         }
1450
1451         if (strcmp(tokens[4], "bsz") != 0) {
1452                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1453                 return;
1454         }
1455
1456         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1457                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1458                 return;
1459         }
1460
1461         t0 = 6;
1462
1463         if (strcmp(tokens[t0], "link") == 0) {
1464                 if (n_tokens < t0 + 4) {
1465                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1466                                 "pipeline port in link");
1467                         return;
1468                 }
1469
1470                 p.type = PORT_IN_RXQ;
1471
1472                 p.dev_name = tokens[t0 + 1];
1473
1474                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
1475                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
1476                         return;
1477                 }
1478
1479                 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1480                         snprintf(out, out_size, MSG_ARG_INVALID,
1481                                 "queue_id");
1482                         return;
1483                 }
1484                 t0 += 4;
1485         } else if (strcmp(tokens[t0], "swq") == 0) {
1486                 if (n_tokens < t0 + 2) {
1487                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1488                                 "pipeline port in swq");
1489                         return;
1490                 }
1491
1492                 p.type = PORT_IN_SWQ;
1493
1494                 p.dev_name = tokens[t0 + 1];
1495
1496                 t0 += 2;
1497         } else if (strcmp(tokens[t0], "tmgr") == 0) {
1498                 if (n_tokens < t0 + 2) {
1499                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1500                                 "pipeline port in tmgr");
1501                         return;
1502                 }
1503
1504                 p.type = PORT_IN_TMGR;
1505
1506                 p.dev_name = tokens[t0 + 1];
1507
1508                 t0 += 2;
1509         } else if (strcmp(tokens[t0], "tap") == 0) {
1510                 if (n_tokens < t0 + 6) {
1511                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1512                                 "pipeline port in tap");
1513                         return;
1514                 }
1515
1516                 p.type = PORT_IN_TAP;
1517
1518                 p.dev_name = tokens[t0 + 1];
1519
1520                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
1521                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1522                                 "mempool");
1523                         return;
1524                 }
1525
1526                 p.tap.mempool_name = tokens[t0 + 3];
1527
1528                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
1529                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1530                                 "mtu");
1531                         return;
1532                 }
1533
1534                 if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
1535                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
1536                         return;
1537                 }
1538
1539                 t0 += 6;
1540         } else if (strcmp(tokens[t0], "kni") == 0) {
1541                 if (n_tokens < t0 + 2) {
1542                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1543                                 "pipeline port in kni");
1544                         return;
1545                 }
1546
1547                 p.type = PORT_IN_KNI;
1548
1549                 p.dev_name = tokens[t0 + 1];
1550
1551                 t0 += 2;
1552         } else if (strcmp(tokens[t0], "source") == 0) {
1553                 if (n_tokens < t0 + 6) {
1554                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1555                                 "pipeline port in source");
1556                         return;
1557                 }
1558
1559                 p.type = PORT_IN_SOURCE;
1560
1561                 p.dev_name = NULL;
1562
1563                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
1564                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1565                                 "mempool");
1566                         return;
1567                 }
1568
1569                 p.source.mempool_name = tokens[t0 + 2];
1570
1571                 if (strcmp(tokens[t0 + 3], "file") != 0) {
1572                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1573                                 "file");
1574                         return;
1575                 }
1576
1577                 p.source.file_name = tokens[t0 + 4];
1578
1579                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
1580                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1581                                 "bpp");
1582                         return;
1583                 }
1584
1585                 if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) {
1586                         snprintf(out, out_size, MSG_ARG_INVALID,
1587                                 "n_bytes_per_pkt");
1588                         return;
1589                 }
1590
1591                 t0 += 7;
1592         } else {
1593                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1594                 return;
1595         }
1596
1597         p.action_profile_name = NULL;
1598         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1599                 if (n_tokens < t0 + 2) {
1600                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1601                         return;
1602                 }
1603
1604                 p.action_profile_name = tokens[t0 + 1];
1605
1606                 t0 += 2;
1607         }
1608
1609         enabled = 1;
1610         if ((n_tokens > t0) &&
1611                 (strcmp(tokens[t0], "disabled") == 0)) {
1612                 enabled = 0;
1613
1614                 t0 += 1;
1615         }
1616
1617         if (n_tokens != t0) {
1618                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1619                 return;
1620         }
1621
1622         status = pipeline_port_in_create(pipeline_name,
1623                 &p, enabled);
1624         if (status) {
1625                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1626                 return;
1627         }
1628 }
1629
1630 static const char cmd_pipeline_port_out_help[] =
1631 "pipeline <pipeline_name> port out\n"
1632 "   bsz <burst_size>\n"
1633 "   link <link_name> txq <txq_id>\n"
1634 "   | swq <swq_name>\n"
1635 "   | tmgr <tmgr_name>\n"
1636 "   | tap <tap_name>\n"
1637 "   | kni <kni_name>\n"
1638 "   | sink [file <file_name> pkts <max_n_pkts>]\n";
1639
1640 static void
1641 cmd_pipeline_port_out(char **tokens,
1642         uint32_t n_tokens,
1643         char *out,
1644         size_t out_size)
1645 {
1646         struct port_out_params p;
1647         char *pipeline_name;
1648         int status;
1649
1650         memset(&p, 0, sizeof(p));
1651
1652         if (n_tokens < 7) {
1653                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1654                 return;
1655         }
1656
1657         pipeline_name = tokens[1];
1658
1659         if (strcmp(tokens[2], "port") != 0) {
1660                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1661                 return;
1662         }
1663
1664         if (strcmp(tokens[3], "out") != 0) {
1665                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1666                 return;
1667         }
1668
1669         if (strcmp(tokens[4], "bsz") != 0) {
1670                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1671                 return;
1672         }
1673
1674         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1675                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1676                 return;
1677         }
1678
1679         if (strcmp(tokens[6], "link") == 0) {
1680                 if (n_tokens != 10) {
1681                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1682                                 "pipeline port out link");
1683                         return;
1684                 }
1685
1686                 p.type = PORT_OUT_TXQ;
1687
1688                 p.dev_name = tokens[7];
1689
1690                 if (strcmp(tokens[8], "txq") != 0) {
1691                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1692                         return;
1693                 }
1694
1695                 if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
1696                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1697                         return;
1698                 }
1699         } else if (strcmp(tokens[6], "swq") == 0) {
1700                 if (n_tokens != 8) {
1701                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1702                                 "pipeline port out swq");
1703                         return;
1704                 }
1705
1706                 p.type = PORT_OUT_SWQ;
1707
1708                 p.dev_name = tokens[7];
1709         } else if (strcmp(tokens[6], "tmgr") == 0) {
1710                 if (n_tokens != 8) {
1711                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1712                                 "pipeline port out tmgr");
1713                         return;
1714                 }
1715
1716                 p.type = PORT_OUT_TMGR;
1717
1718                 p.dev_name = tokens[7];
1719         } else if (strcmp(tokens[6], "tap") == 0) {
1720                 if (n_tokens != 8) {
1721                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1722                                 "pipeline port out tap");
1723                         return;
1724                 }
1725
1726                 p.type = PORT_OUT_TAP;
1727
1728                 p.dev_name = tokens[7];
1729         } else if (strcmp(tokens[6], "kni") == 0) {
1730                 if (n_tokens != 8) {
1731                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1732                                 "pipeline port out kni");
1733                         return;
1734                 }
1735
1736                 p.type = PORT_OUT_KNI;
1737
1738                 p.dev_name = tokens[7];
1739         } else if (strcmp(tokens[6], "sink") == 0) {
1740                 if ((n_tokens != 7) && (n_tokens != 11)) {
1741                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1742                                 "pipeline port out sink");
1743                         return;
1744                 }
1745
1746                 p.type = PORT_OUT_SINK;
1747
1748                 p.dev_name = NULL;
1749
1750                 if (n_tokens == 7) {
1751                         p.sink.file_name = NULL;
1752                         p.sink.max_n_pkts = 0;
1753                 } else {
1754                         if (strcmp(tokens[7], "file") != 0) {
1755                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1756                                         "file");
1757                                 return;
1758                         }
1759
1760                         p.sink.file_name = tokens[8];
1761
1762                         if (strcmp(tokens[9], "pkts") != 0) {
1763                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1764                                 return;
1765                         }
1766
1767                         if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) {
1768                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1769                                 return;
1770                         }
1771                 }
1772         } else {
1773                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1774                 return;
1775         }
1776
1777         status = pipeline_port_out_create(pipeline_name, &p);
1778         if (status) {
1779                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1780                 return;
1781         }
1782 }
1783
1784 static const char cmd_pipeline_table_help[] =
1785 "pipeline <pipeline_name> table\n"
1786 "       match\n"
1787 "       acl\n"
1788 "           ipv4 | ipv6\n"
1789 "           offset <ip_header_offset>\n"
1790 "           size <n_rules>\n"
1791 "       | array\n"
1792 "           offset <key_offset>\n"
1793 "           size <n_keys>\n"
1794 "       | hash\n"
1795 "           ext | lru\n"
1796 "           key <key_size>\n"
1797 "           mask <key_mask>\n"
1798 "           offset <key_offset>\n"
1799 "           buckets <n_buckets>\n"
1800 "           size <n_keys>\n"
1801 "       | lpm\n"
1802 "           ipv4 | ipv6\n"
1803 "           offset <ip_header_offset>\n"
1804 "           size <n_rules>\n"
1805 "       | stub\n"
1806 "   [action <table_action_profile_name>]\n";
1807
1808 static void
1809 cmd_pipeline_table(char **tokens,
1810         uint32_t n_tokens,
1811         char *out,
1812         size_t out_size)
1813 {
1814         uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1815         struct table_params p;
1816         char *pipeline_name;
1817         uint32_t t0;
1818         int status;
1819
1820         if (n_tokens < 5) {
1821                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1822                 return;
1823         }
1824
1825         pipeline_name = tokens[1];
1826
1827         if (strcmp(tokens[2], "table") != 0) {
1828                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1829                 return;
1830         }
1831
1832         if (strcmp(tokens[3], "match") != 0) {
1833                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
1834                 return;
1835         }
1836
1837         t0 = 4;
1838         if (strcmp(tokens[t0], "acl") == 0) {
1839                 if (n_tokens < t0 + 6) {
1840                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1841                                 "pipeline table acl");
1842                         return;
1843                 }
1844
1845                 p.match_type = TABLE_ACL;
1846
1847                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
1848                         p.match.acl.ip_version = 1;
1849                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
1850                         p.match.acl.ip_version = 0;
1851                 else {
1852                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1853                                 "ipv4 or ipv6");
1854                         return;
1855                 }
1856
1857                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1858                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1859                         return;
1860                 }
1861
1862                 if (parser_read_uint32(&p.match.acl.ip_header_offset,
1863                         tokens[t0 + 3]) != 0) {
1864                         snprintf(out, out_size, MSG_ARG_INVALID,
1865                                 "ip_header_offset");
1866                         return;
1867                 }
1868
1869                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1870                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1871                         return;
1872                 }
1873
1874                 if (parser_read_uint32(&p.match.acl.n_rules,
1875                         tokens[t0 + 5]) != 0) {
1876                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1877                         return;
1878                 }
1879
1880                 t0 += 6;
1881         } else if (strcmp(tokens[t0], "array") == 0) {
1882                 if (n_tokens < t0 + 5) {
1883                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1884                                 "pipeline table array");
1885                         return;
1886                 }
1887
1888                 p.match_type = TABLE_ARRAY;
1889
1890                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1891                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1892                         return;
1893                 }
1894
1895                 if (parser_read_uint32(&p.match.array.key_offset,
1896                         tokens[t0 + 2]) != 0) {
1897                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1898                         return;
1899                 }
1900
1901                 if (strcmp(tokens[t0 + 3], "size") != 0) {
1902                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1903                         return;
1904                 }
1905
1906                 if (parser_read_uint32(&p.match.array.n_keys,
1907                         tokens[t0 + 4]) != 0) {
1908                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1909                         return;
1910                 }
1911
1912                 t0 += 5;
1913         } else if (strcmp(tokens[t0], "hash") == 0) {
1914                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
1915
1916                 if (n_tokens < t0 + 12) {
1917                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1918                                 "pipeline table hash");
1919                         return;
1920                 }
1921
1922                 p.match_type = TABLE_HASH;
1923
1924                 if (strcmp(tokens[t0 + 1], "ext") == 0)
1925                         p.match.hash.extendable_bucket = 1;
1926                 else if (strcmp(tokens[t0 + 1], "lru") == 0)
1927                         p.match.hash.extendable_bucket = 0;
1928                 else {
1929                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1930                                 "ext or lru");
1931                         return;
1932                 }
1933
1934                 if (strcmp(tokens[t0 + 2], "key") != 0) {
1935                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
1936                         return;
1937                 }
1938
1939                 if ((parser_read_uint32(&p.match.hash.key_size,
1940                         tokens[t0 + 3]) != 0) ||
1941                         (p.match.hash.key_size == 0) ||
1942                         (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
1943                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
1944                         return;
1945                 }
1946
1947                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
1948                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1949                         return;
1950                 }
1951
1952                 if ((parse_hex_string(tokens[t0 + 5],
1953                         key_mask, &key_mask_size) != 0) ||
1954                         (key_mask_size != p.match.hash.key_size)) {
1955                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1956                         return;
1957                 }
1958                 p.match.hash.key_mask = key_mask;
1959
1960                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
1961                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1962                         return;
1963                 }
1964
1965                 if (parser_read_uint32(&p.match.hash.key_offset,
1966                         tokens[t0 + 7]) != 0) {
1967                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1968                         return;
1969                 }
1970
1971                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
1972                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
1973                         return;
1974                 }
1975
1976                 if (parser_read_uint32(&p.match.hash.n_buckets,
1977                         tokens[t0 + 9]) != 0) {
1978                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
1979                         return;
1980                 }
1981
1982                 if (strcmp(tokens[t0 + 10], "size") != 0) {
1983                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1984                         return;
1985                 }
1986
1987                 if (parser_read_uint32(&p.match.hash.n_keys,
1988                         tokens[t0 + 11]) != 0) {
1989                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1990                         return;
1991                 }
1992
1993                 t0 += 12;
1994         } else if (strcmp(tokens[t0], "lpm") == 0) {
1995                 if (n_tokens < t0 + 6) {
1996                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1997                                 "pipeline table lpm");
1998                         return;
1999                 }
2000
2001                 p.match_type = TABLE_LPM;
2002
2003                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
2004                         p.match.lpm.key_size = 4;
2005                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
2006                         p.match.lpm.key_size = 16;
2007                 else {
2008                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2009                                 "ipv4 or ipv6");
2010                         return;
2011                 }
2012
2013                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
2014                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2015                         return;
2016                 }
2017
2018                 if (parser_read_uint32(&p.match.lpm.key_offset,
2019                         tokens[t0 + 3]) != 0) {
2020                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2021                         return;
2022                 }
2023
2024                 if (strcmp(tokens[t0 + 4], "size") != 0) {
2025                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2026                         return;
2027                 }
2028
2029                 if (parser_read_uint32(&p.match.lpm.n_rules,
2030                         tokens[t0 + 5]) != 0) {
2031                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2032                         return;
2033                 }
2034
2035                 t0 += 6;
2036         } else if (strcmp(tokens[t0], "stub") == 0) {
2037                 p.match_type = TABLE_STUB;
2038
2039                 t0 += 1;
2040         } else {
2041                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
2042                 return;
2043         }
2044
2045         p.action_profile_name = NULL;
2046         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
2047                 if (n_tokens < t0 + 2) {
2048                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
2049                         return;
2050                 }
2051
2052                 p.action_profile_name = tokens[t0 + 1];
2053
2054                 t0 += 2;
2055         }
2056
2057         if (n_tokens > t0) {
2058                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2059                 return;
2060         }
2061
2062         status = pipeline_table_create(pipeline_name, &p);
2063         if (status) {
2064                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2065                 return;
2066         }
2067 }
2068
2069 static const char cmd_pipeline_port_in_table_help[] =
2070 "pipeline <pipeline_name> port in <port_id> table <table_id>\n";
2071
2072 static void
2073 cmd_pipeline_port_in_table(char **tokens,
2074         uint32_t n_tokens,
2075         char *out,
2076         size_t out_size)
2077 {
2078         char *pipeline_name;
2079         uint32_t port_id, table_id;
2080         int status;
2081
2082         if (n_tokens != 7) {
2083                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2084                 return;
2085         }
2086
2087         pipeline_name = tokens[1];
2088
2089         if (strcmp(tokens[2], "port") != 0) {
2090                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2091                 return;
2092         }
2093
2094         if (strcmp(tokens[3], "in") != 0) {
2095                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2096                 return;
2097         }
2098
2099         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2100                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2101                 return;
2102         }
2103
2104         if (strcmp(tokens[5], "table") != 0) {
2105                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2106                 return;
2107         }
2108
2109         if (parser_read_uint32(&table_id, tokens[6]) != 0) {
2110                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2111                 return;
2112         }
2113
2114         status = pipeline_port_in_connect_to_table(pipeline_name,
2115                 port_id,
2116                 table_id);
2117         if (status) {
2118                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2119                 return;
2120         }
2121 }
2122
2123
2124 static const char cmd_pipeline_port_in_stats_help[] =
2125 "pipeline <pipeline_name> port in <port_id> stats read [clear]\n";
2126
2127 #define MSG_PIPELINE_PORT_IN_STATS                         \
2128         "Pkts in: %" PRIu64 "\n"                           \
2129         "Pkts dropped by AH: %" PRIu64 "\n"                \
2130         "Pkts dropped by other: %" PRIu64 "\n"
2131
2132 static void
2133 cmd_pipeline_port_in_stats(char **tokens,
2134         uint32_t n_tokens,
2135         char *out,
2136         size_t out_size)
2137 {
2138         struct rte_pipeline_port_in_stats stats;
2139         char *pipeline_name;
2140         uint32_t port_id;
2141         int clear, status;
2142
2143         if ((n_tokens != 7) && (n_tokens != 8)) {
2144                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2145                 return;
2146         }
2147
2148         pipeline_name = tokens[1];
2149
2150         if (strcmp(tokens[2], "port") != 0) {
2151                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2152                 return;
2153         }
2154
2155         if (strcmp(tokens[3], "in") != 0) {
2156                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2157                 return;
2158         }
2159
2160         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2161                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2162                 return;
2163         }
2164
2165         if (strcmp(tokens[5], "stats") != 0) {
2166                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2167                 return;
2168         }
2169
2170         if (strcmp(tokens[6], "read") != 0) {
2171                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2172                 return;
2173         }
2174
2175         clear = 0;
2176         if (n_tokens == 8) {
2177                 if (strcmp(tokens[7], "clear") != 0) {
2178                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2179                         return;
2180                 }
2181
2182                 clear = 1;
2183         }
2184
2185         status = pipeline_port_in_stats_read(pipeline_name,
2186                 port_id,
2187                 &stats,
2188                 clear);
2189         if (status) {
2190                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2191                 return;
2192         }
2193
2194         snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
2195                 stats.stats.n_pkts_in,
2196                 stats.n_pkts_dropped_by_ah,
2197                 stats.stats.n_pkts_drop);
2198 }
2199
2200
2201 static const char cmd_pipeline_port_in_enable_help[] =
2202 "pipeline <pipeline_name> port in <port_id> enable\n";
2203
2204 static void
2205 cmd_pipeline_port_in_enable(char **tokens,
2206         uint32_t n_tokens,
2207         char *out,
2208         size_t out_size)
2209 {
2210         char *pipeline_name;
2211         uint32_t port_id;
2212         int status;
2213
2214         if (n_tokens != 6) {
2215                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2216                 return;
2217         }
2218
2219         pipeline_name = tokens[1];
2220
2221         if (strcmp(tokens[2], "port") != 0) {
2222                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2223                 return;
2224         }
2225
2226         if (strcmp(tokens[3], "in") != 0) {
2227                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2228                 return;
2229         }
2230
2231         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2232                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2233                 return;
2234         }
2235
2236         if (strcmp(tokens[5], "enable") != 0) {
2237                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2238                 return;
2239         }
2240
2241         status = pipeline_port_in_enable(pipeline_name, port_id);
2242         if (status) {
2243                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2244                 return;
2245         }
2246 }
2247
2248
2249 static const char cmd_pipeline_port_in_disable_help[] =
2250 "pipeline <pipeline_name> port in <port_id> disable\n";
2251
2252 static void
2253 cmd_pipeline_port_in_disable(char **tokens,
2254         uint32_t n_tokens,
2255         char *out,
2256         size_t out_size)
2257 {
2258         char *pipeline_name;
2259         uint32_t port_id;
2260         int status;
2261
2262         if (n_tokens != 6) {
2263                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2264                 return;
2265         }
2266
2267         pipeline_name = tokens[1];
2268
2269         if (strcmp(tokens[2], "port") != 0) {
2270                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2271                 return;
2272         }
2273
2274         if (strcmp(tokens[3], "in") != 0) {
2275                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2276                 return;
2277         }
2278
2279         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2280                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2281                 return;
2282         }
2283
2284         if (strcmp(tokens[5], "disable") != 0) {
2285                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2286                 return;
2287         }
2288
2289         status = pipeline_port_in_disable(pipeline_name, port_id);
2290         if (status) {
2291                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2292                 return;
2293         }
2294 }
2295
2296
2297 static const char cmd_pipeline_port_out_stats_help[] =
2298 "pipeline <pipeline_name> port out <port_id> stats read [clear]\n";
2299
2300 #define MSG_PIPELINE_PORT_OUT_STATS                        \
2301         "Pkts in: %" PRIu64 "\n"                           \
2302         "Pkts dropped by AH: %" PRIu64 "\n"                \
2303         "Pkts dropped by other: %" PRIu64 "\n"
2304
2305 static void
2306 cmd_pipeline_port_out_stats(char **tokens,
2307         uint32_t n_tokens,
2308         char *out,
2309         size_t out_size)
2310 {
2311         struct rte_pipeline_port_out_stats stats;
2312         char *pipeline_name;
2313         uint32_t port_id;
2314         int clear, status;
2315
2316         if ((n_tokens != 7) && (n_tokens != 8)) {
2317                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2318                 return;
2319         }
2320
2321         pipeline_name = tokens[1];
2322
2323         if (strcmp(tokens[2], "port") != 0) {
2324                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2325                 return;
2326         }
2327
2328         if (strcmp(tokens[3], "out") != 0) {
2329                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2330                 return;
2331         }
2332
2333         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2334                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2335                 return;
2336         }
2337
2338         if (strcmp(tokens[5], "stats") != 0) {
2339                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2340                 return;
2341         }
2342
2343         if (strcmp(tokens[6], "read") != 0) {
2344                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2345                 return;
2346         }
2347
2348         clear = 0;
2349         if (n_tokens == 8) {
2350                 if (strcmp(tokens[7], "clear") != 0) {
2351                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2352                         return;
2353                 }
2354
2355                 clear = 1;
2356         }
2357
2358         status = pipeline_port_out_stats_read(pipeline_name,
2359                 port_id,
2360                 &stats,
2361                 clear);
2362         if (status) {
2363                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2364                 return;
2365         }
2366
2367         snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
2368                 stats.stats.n_pkts_in,
2369                 stats.n_pkts_dropped_by_ah,
2370                 stats.stats.n_pkts_drop);
2371 }
2372
2373
2374 static const char cmd_pipeline_table_stats_help[] =
2375 "pipeline <pipeline_name> table <table_id> stats read [clear]\n";
2376
2377 #define MSG_PIPELINE_TABLE_STATS                                     \
2378         "Pkts in: %" PRIu64 "\n"                                     \
2379         "Pkts in with lookup miss: %" PRIu64 "\n"                    \
2380         "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
2381         "Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
2382         "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
2383         "Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
2384
2385 static void
2386 cmd_pipeline_table_stats(char **tokens,
2387         uint32_t n_tokens,
2388         char *out,
2389         size_t out_size)
2390 {
2391         struct rte_pipeline_table_stats stats;
2392         char *pipeline_name;
2393         uint32_t table_id;
2394         int clear, status;
2395
2396         if ((n_tokens != 6) && (n_tokens != 7)) {
2397                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2398                 return;
2399         }
2400
2401         pipeline_name = tokens[1];
2402
2403         if (strcmp(tokens[2], "table") != 0) {
2404                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2405                 return;
2406         }
2407
2408         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
2409                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2410                 return;
2411         }
2412
2413         if (strcmp(tokens[4], "stats") != 0) {
2414                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2415                 return;
2416         }
2417
2418         if (strcmp(tokens[5], "read") != 0) {
2419                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2420                 return;
2421         }
2422
2423         clear = 0;
2424         if (n_tokens == 7) {
2425                 if (strcmp(tokens[6], "clear") != 0) {
2426                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2427                         return;
2428                 }
2429
2430                 clear = 1;
2431         }
2432
2433         status = pipeline_table_stats_read(pipeline_name,
2434                 table_id,
2435                 &stats,
2436                 clear);
2437         if (status) {
2438                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2439                 return;
2440         }
2441
2442         snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
2443                 stats.stats.n_pkts_in,
2444                 stats.stats.n_pkts_lookup_miss,
2445                 stats.n_pkts_dropped_by_lkp_hit_ah,
2446                 stats.n_pkts_dropped_lkp_hit,
2447                 stats.n_pkts_dropped_by_lkp_miss_ah,
2448                 stats.n_pkts_dropped_lkp_miss);
2449 }
2450
2451 /**
2452  * <match> ::=
2453  *
2454  * match
2455  *    acl
2456  *       priority <priority>
2457  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
2458  *       <sp0> <sp1> <dp0> <dp1> <proto>
2459  *    | array <pos>
2460  *    | hash
2461  *       raw <key>
2462  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2463  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2464  *       | ipv4_addr <addr>
2465  *       | ipv6_addr <addr>
2466  *       | qinq <svlan> <cvlan>
2467  *    | lpm
2468  *       ipv4 | ipv6 <addr> <depth>
2469  */
2470 struct pkt_key_qinq {
2471         uint16_t ethertype_svlan;
2472         uint16_t svlan;
2473         uint16_t ethertype_cvlan;
2474         uint16_t cvlan;
2475 } __attribute__((__packed__));
2476
2477 struct pkt_key_ipv4_5tuple {
2478         uint8_t time_to_live;
2479         uint8_t proto;
2480         uint16_t hdr_checksum;
2481         uint32_t sa;
2482         uint32_t da;
2483         uint16_t sp;
2484         uint16_t dp;
2485 } __attribute__((__packed__));
2486
2487 struct pkt_key_ipv6_5tuple {
2488         uint16_t payload_length;
2489         uint8_t proto;
2490         uint8_t hop_limit;
2491         uint8_t sa[16];
2492         uint8_t da[16];
2493         uint16_t sp;
2494         uint16_t dp;
2495 } __attribute__((__packed__));
2496
2497 struct pkt_key_ipv4_addr {
2498         uint32_t addr;
2499 } __attribute__((__packed__));
2500
2501 struct pkt_key_ipv6_addr {
2502         uint8_t addr[16];
2503 } __attribute__((__packed__));
2504
2505 static uint32_t
2506 parse_match(char **tokens,
2507         uint32_t n_tokens,
2508         char *out,
2509         size_t out_size,
2510         struct table_rule_match *m)
2511 {
2512         memset(m, 0, sizeof(*m));
2513
2514         if (n_tokens < 2)
2515                 return 0;
2516
2517         if (strcmp(tokens[0], "match") != 0) {
2518                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2519                 return 0;
2520         }
2521
2522         if (strcmp(tokens[1], "acl") == 0) {
2523                 if (n_tokens < 14) {
2524                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2525                         return 0;
2526                 }
2527
2528                 m->match_type = TABLE_ACL;
2529
2530                 if (strcmp(tokens[2], "priority") != 0) {
2531                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
2532                         return 0;
2533                 }
2534
2535                 if (parser_read_uint32(&m->match.acl.priority,
2536                         tokens[3]) != 0) {
2537                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
2538                         return 0;
2539                 }
2540
2541                 if (strcmp(tokens[4], "ipv4") == 0) {
2542                         struct in_addr saddr, daddr;
2543
2544                         m->match.acl.ip_version = 1;
2545
2546                         if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
2547                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2548                                 return 0;
2549                         }
2550                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
2551
2552                         if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
2553                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2554                                 return 0;
2555                         }
2556                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
2557                 } else if (strcmp(tokens[4], "ipv6") == 0) {
2558                         struct in6_addr saddr, daddr;
2559
2560                         m->match.acl.ip_version = 0;
2561
2562                         if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
2563                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2564                                 return 0;
2565                         }
2566                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2567
2568                         if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2569                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2570                                 return 0;
2571                         }
2572                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
2573                 } else {
2574                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2575                                 "ipv4 or ipv6");
2576                         return 0;
2577                 }
2578
2579                 if (parser_read_uint32(&m->match.acl.sa_depth,
2580                         tokens[6]) != 0) {
2581                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
2582                         return 0;
2583                 }
2584
2585                 if (parser_read_uint32(&m->match.acl.da_depth,
2586                         tokens[8]) != 0) {
2587                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
2588                         return 0;
2589                 }
2590
2591                 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
2592                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
2593                         return 0;
2594                 }
2595
2596                 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
2597                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
2598                         return 0;
2599                 }
2600
2601                 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
2602                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
2603                         return 0;
2604                 }
2605
2606                 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
2607                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
2608                         return 0;
2609                 }
2610
2611                 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
2612                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
2613                         return 0;
2614                 }
2615
2616                 m->match.acl.proto_mask = 0xff;
2617
2618                 return 14;
2619         } /* acl */
2620
2621         if (strcmp(tokens[1], "array") == 0) {
2622                 if (n_tokens < 3) {
2623                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2624                         return 0;
2625                 }
2626
2627                 m->match_type = TABLE_ARRAY;
2628
2629                 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
2630                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
2631                         return 0;
2632                 }
2633
2634                 return 3;
2635         } /* array */
2636
2637         if (strcmp(tokens[1], "hash") == 0) {
2638                 if (n_tokens < 3) {
2639                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2640                         return 0;
2641                 }
2642
2643                 m->match_type = TABLE_HASH;
2644
2645                 if (strcmp(tokens[2], "raw") == 0) {
2646                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
2647
2648                         if (n_tokens < 4) {
2649                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2650                                         tokens[0]);
2651                                 return 0;
2652                         }
2653
2654                         if (parse_hex_string(tokens[3],
2655                                 m->match.hash.key, &key_size) != 0) {
2656                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
2657                                 return 0;
2658                         }
2659
2660                         return 4;
2661                 } /* hash raw */
2662
2663                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
2664                         struct pkt_key_ipv4_5tuple *ipv4 =
2665                                 (struct pkt_key_ipv4_5tuple *) m->match.hash.key;
2666                         struct in_addr saddr, daddr;
2667                         uint16_t sp, dp;
2668                         uint8_t proto;
2669
2670                         if (n_tokens < 8) {
2671                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2672                                         tokens[0]);
2673                                 return 0;
2674                         }
2675
2676                         if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
2677                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2678                                 return 0;
2679                         }
2680
2681                         if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
2682                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2683                                 return 0;
2684                         }
2685
2686                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2687                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2688                                 return 0;
2689                         }
2690
2691                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2692                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2693                                 return 0;
2694                         }
2695
2696                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2697                                 snprintf(out, out_size, MSG_ARG_INVALID,
2698                                         "proto");
2699                                 return 0;
2700                         }
2701
2702                         ipv4->sa = saddr.s_addr;
2703                         ipv4->da = daddr.s_addr;
2704                         ipv4->sp = rte_cpu_to_be_16(sp);
2705                         ipv4->dp = rte_cpu_to_be_16(dp);
2706                         ipv4->proto = proto;
2707
2708                         return 8;
2709                 } /* hash ipv4_5tuple */
2710
2711                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
2712                         struct pkt_key_ipv6_5tuple *ipv6 =
2713                                 (struct pkt_key_ipv6_5tuple *) m->match.hash.key;
2714                         struct in6_addr saddr, daddr;
2715                         uint16_t sp, dp;
2716                         uint8_t proto;
2717
2718                         if (n_tokens < 8) {
2719                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2720                                         tokens[0]);
2721                                 return 0;
2722                         }
2723
2724                         if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
2725                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2726                                 return 0;
2727                         }
2728
2729                         if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
2730                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2731                                 return 0;
2732                         }
2733
2734                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2735                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2736                                 return 0;
2737                         }
2738
2739                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2740                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2741                                 return 0;
2742                         }
2743
2744                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2745                                 snprintf(out, out_size, MSG_ARG_INVALID,
2746                                         "proto");
2747                                 return 0;
2748                         }
2749
2750                         memcpy(ipv6->sa, saddr.s6_addr, 16);
2751                         memcpy(ipv6->da, daddr.s6_addr, 16);
2752                         ipv6->sp = rte_cpu_to_be_16(sp);
2753                         ipv6->dp = rte_cpu_to_be_16(dp);
2754                         ipv6->proto = proto;
2755
2756                         return 8;
2757                 } /* hash ipv6_5tuple */
2758
2759                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
2760                         struct pkt_key_ipv4_addr *ipv4_addr =
2761                                 (struct pkt_key_ipv4_addr *) m->match.hash.key;
2762                         struct in_addr addr;
2763
2764                         if (n_tokens < 4) {
2765                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2766                                         tokens[0]);
2767                                 return 0;
2768                         }
2769
2770                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2771                                 snprintf(out, out_size, MSG_ARG_INVALID,
2772                                         "addr");
2773                                 return 0;
2774                         }
2775
2776                         ipv4_addr->addr = addr.s_addr;
2777
2778                         return 4;
2779                 } /* hash ipv4_addr */
2780
2781                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
2782                         struct pkt_key_ipv6_addr *ipv6_addr =
2783                                 (struct pkt_key_ipv6_addr *) m->match.hash.key;
2784                         struct in6_addr addr;
2785
2786                         if (n_tokens < 4) {
2787                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2788                                         tokens[0]);
2789                                 return 0;
2790                         }
2791
2792                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2793                                 snprintf(out, out_size, MSG_ARG_INVALID,
2794                                         "addr");
2795                                 return 0;
2796                         }
2797
2798                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
2799
2800                         return 4;
2801                 } /* hash ipv6_5tuple */
2802
2803                 if (strcmp(tokens[2], "qinq") == 0) {
2804                         struct pkt_key_qinq *qinq =
2805                                 (struct pkt_key_qinq *) m->match.hash.key;
2806                         uint16_t svlan, cvlan;
2807
2808                         if (n_tokens < 5) {
2809                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2810                                         tokens[0]);
2811                                 return 0;
2812                         }
2813
2814                         if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
2815                                 (svlan > 0xFFF)) {
2816                                 snprintf(out, out_size, MSG_ARG_INVALID,
2817                                         "svlan");
2818                                 return 0;
2819                         }
2820
2821                         if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
2822                                 (cvlan > 0xFFF)) {
2823                                 snprintf(out, out_size, MSG_ARG_INVALID,
2824                                         "cvlan");
2825                                 return 0;
2826                         }
2827
2828                         qinq->svlan = rte_cpu_to_be_16(svlan);
2829                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
2830
2831                         return 5;
2832                 } /* hash qinq */
2833
2834                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2835                 return 0;
2836         } /* hash */
2837
2838         if (strcmp(tokens[1], "lpm") == 0) {
2839                 if (n_tokens < 5) {
2840                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2841                         return 0;
2842                 }
2843
2844                 m->match_type = TABLE_LPM;
2845
2846                 if (strcmp(tokens[2], "ipv4") == 0) {
2847                         struct in_addr addr;
2848
2849                         m->match.lpm.ip_version = 1;
2850
2851                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2852                                 snprintf(out, out_size, MSG_ARG_INVALID,
2853                                         "addr");
2854                                 return 0;
2855                         }
2856
2857                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
2858                 } else if (strcmp(tokens[2], "ipv6") == 0) {
2859                         struct in6_addr addr;
2860
2861                         m->match.lpm.ip_version = 0;
2862
2863                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2864                                 snprintf(out, out_size, MSG_ARG_INVALID,
2865                                         "addr");
2866                                 return 0;
2867                         }
2868
2869                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
2870                 } else {
2871                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2872                                 "ipv4 or ipv6");
2873                         return 0;
2874                 }
2875
2876                 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
2877                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
2878                         return 0;
2879                 }
2880
2881                 return 5;
2882         } /* lpm */
2883
2884         snprintf(out, out_size, MSG_ARG_MISMATCH,
2885                 "acl or array or hash or lpm");
2886         return 0;
2887 }
2888
2889 /**
2890  * table_action ::=
2891  *
2892  * action
2893  *    fwd
2894  *       drop
2895  *       | port <port_id>
2896  *       | meta
2897  *       | table <table_id>
2898  *    [balance <out0> ... <out7>]
2899  *    [meter
2900  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2901  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2902  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2903  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
2904  *    [tm subport <subport_id> pipe <pipe_id>]
2905  *    [encap
2906  *       ether <da> <sa>
2907  *       | vlan <da> <sa> <pcp> <dei> <vid>
2908  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
2909  *       | mpls unicast | multicast
2910  *          <da> <sa>
2911  *          label0 <label> <tc> <ttl>
2912  *          [label1 <label> <tc> <ttl>
2913  *          [label2 <label> <tc> <ttl>
2914  *          [label3 <label> <tc> <ttl>]]]
2915  *       | pppoe <da> <sa> <session_id>
2916  *       | vxlan ether <da> <sa>
2917  *          [vlan <pcp> <dei> <vid>]
2918  *          ipv4 <sa> <da> <dscp> <ttl>
2919  *          | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit>
2920  *          udp <sp> <dp>
2921  *          vxlan <vni>]
2922  *    [nat ipv4 | ipv6 <addr> <port>]
2923  *    [ttl dec | keep]
2924  *    [stats]
2925  *    [time]
2926  *
2927  * where:
2928  *    <pa> ::= g | y | r | drop
2929  */
2930 static uint32_t
2931 parse_table_action_fwd(char **tokens,
2932         uint32_t n_tokens,
2933         struct table_rule_action *a)
2934 {
2935         if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
2936                 return 0;
2937
2938         tokens++;
2939         n_tokens--;
2940
2941         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
2942                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
2943                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2944                 return 1 + 1;
2945         }
2946
2947         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
2948                 uint32_t id;
2949
2950                 if ((n_tokens < 2) ||
2951                         parser_read_uint32(&id, tokens[1]))
2952                         return 0;
2953
2954                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
2955                 a->fwd.id = id;
2956                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2957                 return 1 + 2;
2958         }
2959
2960         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
2961                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
2962                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2963                 return 1 + 1;
2964         }
2965
2966         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
2967                 uint32_t id;
2968
2969                 if ((n_tokens < 2) ||
2970                         parser_read_uint32(&id, tokens[1]))
2971                         return 0;
2972
2973                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
2974                 a->fwd.id = id;
2975                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2976                 return 1 + 2;
2977         }
2978
2979         return 0;
2980 }
2981
2982 static uint32_t
2983 parse_table_action_balance(char **tokens,
2984         uint32_t n_tokens,
2985         struct table_rule_action *a)
2986 {
2987         uint32_t i;
2988
2989         if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0))
2990                 return 0;
2991
2992         tokens++;
2993         n_tokens--;
2994
2995         if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE)
2996                 return 0;
2997
2998         for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++)
2999                 if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
3000                         return 0;
3001
3002         a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
3003         return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE;
3004
3005 }
3006
3007 static int
3008 parse_policer_action(char *token, enum rte_table_action_policer *a)
3009 {
3010         if (strcmp(token, "g") == 0) {
3011                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
3012                 return 0;
3013         }
3014
3015         if (strcmp(token, "y") == 0) {
3016                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
3017                 return 0;
3018         }
3019
3020         if (strcmp(token, "r") == 0) {
3021                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
3022                 return 0;
3023         }
3024
3025         if (strcmp(token, "drop") == 0) {
3026                 *a = RTE_TABLE_ACTION_POLICER_DROP;
3027                 return 0;
3028         }
3029
3030         return -1;
3031 }
3032
3033 static uint32_t
3034 parse_table_action_meter_tc(char **tokens,
3035         uint32_t n_tokens,
3036         struct rte_table_action_mtr_tc_params *mtr)
3037 {
3038         if ((n_tokens < 9) ||
3039                 strcmp(tokens[0], "meter") ||
3040                 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
3041                 strcmp(tokens[2], "policer") ||
3042                 strcmp(tokens[3], "g") ||
3043                 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
3044                 strcmp(tokens[5], "y") ||
3045                 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
3046                 strcmp(tokens[7], "r") ||
3047                 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
3048                 return 0;
3049
3050         return 9;
3051 }
3052
3053 static uint32_t
3054 parse_table_action_meter(char **tokens,
3055         uint32_t n_tokens,
3056         struct table_rule_action *a)
3057 {
3058         if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
3059                 return 0;
3060
3061         tokens++;
3062         n_tokens--;
3063
3064         if ((n_tokens < 10) ||
3065                 strcmp(tokens[0], "tc0") ||
3066                 (parse_table_action_meter_tc(tokens + 1,
3067                         n_tokens - 1,
3068                         &a->mtr.mtr[0]) == 0))
3069                 return 0;
3070
3071         tokens += 10;
3072         n_tokens -= 10;
3073
3074         if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
3075                 a->mtr.tc_mask = 1;
3076                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3077                 return 1 + 10;
3078         }
3079
3080         if ((n_tokens < 30) ||
3081                 (parse_table_action_meter_tc(tokens + 1,
3082                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
3083                 strcmp(tokens[10], "tc2") ||
3084                 (parse_table_action_meter_tc(tokens + 11,
3085                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
3086                 strcmp(tokens[20], "tc3") ||
3087                 (parse_table_action_meter_tc(tokens + 21,
3088                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
3089                 return 0;
3090
3091         a->mtr.tc_mask = 0xF;
3092         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3093         return 1 + 10 + 3 * 10;
3094 }
3095
3096 static uint32_t
3097 parse_table_action_tm(char **tokens,
3098         uint32_t n_tokens,
3099         struct table_rule_action *a)
3100 {
3101         uint32_t subport_id, pipe_id;
3102
3103         if ((n_tokens < 5) ||
3104                 strcmp(tokens[0], "tm") ||
3105                 strcmp(tokens[1], "subport") ||
3106                 parser_read_uint32(&subport_id, tokens[2]) ||
3107                 strcmp(tokens[3], "pipe") ||
3108                 parser_read_uint32(&pipe_id, tokens[4]))
3109                 return 0;
3110
3111         a->tm.subport_id = subport_id;
3112         a->tm.pipe_id = pipe_id;
3113         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
3114         return 5;
3115 }
3116
3117 static uint32_t
3118 parse_table_action_encap(char **tokens,
3119         uint32_t n_tokens,
3120         struct table_rule_action *a)
3121 {
3122         if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
3123                 return 0;
3124
3125         tokens++;
3126         n_tokens--;
3127
3128         /* ether */
3129         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
3130                 if ((n_tokens < 3) ||
3131                         parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
3132                         parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
3133                         return 0;
3134
3135                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
3136                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3137                 return 1 + 3;
3138         }
3139
3140         /* vlan */
3141         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
3142                 uint32_t pcp, dei, vid;
3143
3144                 if ((n_tokens < 6) ||
3145                         parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
3146                         parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
3147                         parser_read_uint32(&pcp, tokens[3]) ||
3148                         (pcp > 0x7) ||
3149                         parser_read_uint32(&dei, tokens[4]) ||
3150                         (dei > 0x1) ||
3151                         parser_read_uint32(&vid, tokens[5]) ||
3152                         (vid > 0xFFF))
3153                         return 0;
3154
3155                 a->encap.vlan.vlan.pcp = pcp & 0x7;
3156                 a->encap.vlan.vlan.dei = dei & 0x1;
3157                 a->encap.vlan.vlan.vid = vid & 0xFFF;
3158                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
3159                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3160                 return 1 + 6;
3161         }
3162
3163         /* qinq */
3164         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
3165                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
3166                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3167
3168                 if ((n_tokens < 9) ||
3169                         parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
3170                         parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
3171                         parser_read_uint32(&svlan_pcp, tokens[3]) ||
3172                         (svlan_pcp > 0x7) ||
3173                         parser_read_uint32(&svlan_dei, tokens[4]) ||
3174                         (svlan_dei > 0x1) ||
3175                         parser_read_uint32(&svlan_vid, tokens[5]) ||
3176                         (svlan_vid > 0xFFF) ||
3177                         parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3178                         (cvlan_pcp > 0x7) ||
3179                         parser_read_uint32(&cvlan_dei, tokens[7]) ||
3180                         (cvlan_dei > 0x1) ||
3181                         parser_read_uint32(&cvlan_vid, tokens[8]) ||
3182                         (cvlan_vid > 0xFFF))
3183                         return 0;
3184
3185                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
3186                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
3187                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
3188                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
3189                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
3190                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
3191                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
3192                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3193                 return 1 + 9;
3194         }
3195
3196         /* mpls */
3197         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
3198                 uint32_t label, tc, ttl;
3199
3200                 if (n_tokens < 8)
3201                         return 0;
3202
3203                 if (strcmp(tokens[1], "unicast") == 0)
3204                         a->encap.mpls.unicast = 1;
3205                 else if (strcmp(tokens[1], "multicast") == 0)
3206                         a->encap.mpls.unicast = 0;
3207                 else
3208                         return 0;
3209
3210                 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
3211                         parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
3212                         strcmp(tokens[4], "label0") ||
3213                         parser_read_uint32(&label, tokens[5]) ||
3214                         (label > 0xFFFFF) ||
3215                         parser_read_uint32(&tc, tokens[6]) ||
3216                         (tc > 0x7) ||
3217                         parser_read_uint32(&ttl, tokens[7]) ||
3218                         (ttl > 0x3F))
3219                         return 0;
3220
3221                 a->encap.mpls.mpls[0].label = label;
3222                 a->encap.mpls.mpls[0].tc = tc;
3223                 a->encap.mpls.mpls[0].ttl = ttl;
3224
3225                 tokens += 8;
3226                 n_tokens -= 8;
3227
3228                 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
3229                         a->encap.mpls.mpls_count = 1;
3230                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3231                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3232                         return 1 + 8;
3233                 }
3234
3235                 if ((n_tokens < 4) ||
3236                         parser_read_uint32(&label, tokens[1]) ||
3237                         (label > 0xFFFFF) ||
3238                         parser_read_uint32(&tc, tokens[2]) ||
3239                         (tc > 0x7) ||
3240                         parser_read_uint32(&ttl, tokens[3]) ||
3241                         (ttl > 0x3F))
3242                         return 0;
3243
3244                 a->encap.mpls.mpls[1].label = label;
3245                 a->encap.mpls.mpls[1].tc = tc;
3246                 a->encap.mpls.mpls[1].ttl = ttl;
3247
3248                 tokens += 4;
3249                 n_tokens -= 4;
3250
3251                 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
3252                         a->encap.mpls.mpls_count = 2;
3253                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3254                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3255                         return 1 + 8 + 4;
3256                 }
3257
3258                 if ((n_tokens < 4) ||
3259                         parser_read_uint32(&label, tokens[1]) ||
3260                         (label > 0xFFFFF) ||
3261                         parser_read_uint32(&tc, tokens[2]) ||
3262                         (tc > 0x7) ||
3263                         parser_read_uint32(&ttl, tokens[3]) ||
3264                         (ttl > 0x3F))
3265                         return 0;
3266
3267                 a->encap.mpls.mpls[2].label = label;
3268                 a->encap.mpls.mpls[2].tc = tc;
3269                 a->encap.mpls.mpls[2].ttl = ttl;
3270
3271                 tokens += 4;
3272                 n_tokens -= 4;
3273
3274                 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
3275                         a->encap.mpls.mpls_count = 3;
3276                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3277                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3278                         return 1 + 8 + 4 + 4;
3279                 }
3280
3281                 if ((n_tokens < 4) ||
3282                         parser_read_uint32(&label, tokens[1]) ||
3283                         (label > 0xFFFFF) ||
3284                         parser_read_uint32(&tc, tokens[2]) ||
3285                         (tc > 0x7) ||
3286                         parser_read_uint32(&ttl, tokens[3]) ||
3287                         (ttl > 0x3F))
3288                         return 0;
3289
3290                 a->encap.mpls.mpls[3].label = label;
3291                 a->encap.mpls.mpls[3].tc = tc;
3292                 a->encap.mpls.mpls[3].ttl = ttl;
3293
3294                 a->encap.mpls.mpls_count = 4;
3295                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3296                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3297                 return 1 + 8 + 4 + 4 + 4;
3298         }
3299
3300         /* pppoe */
3301         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3302                 if ((n_tokens < 4) ||
3303                         parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3304                         parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3305                         parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3306                                 tokens[3]))
3307                         return 0;
3308
3309                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3310                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3311                 return 1 + 4;
3312         }
3313
3314         /* vxlan */
3315         if (n_tokens && (strcmp(tokens[0], "vxlan") == 0)) {
3316                 uint32_t n = 0;
3317
3318                 n_tokens--;
3319                 tokens++;
3320                 n++;
3321
3322                 /* ether <da> <sa> */
3323                 if ((n_tokens < 3) ||
3324                         strcmp(tokens[0], "ether") ||
3325                         parse_mac_addr(tokens[1], &a->encap.vxlan.ether.da) ||
3326                         parse_mac_addr(tokens[2], &a->encap.vxlan.ether.sa))
3327                         return 0;
3328
3329                 n_tokens -= 3;
3330                 tokens += 3;
3331                 n += 3;
3332
3333                 /* [vlan <pcp> <dei> <vid>] */
3334                 if (strcmp(tokens[0], "vlan") == 0) {
3335                         uint32_t pcp, dei, vid;
3336
3337                         if ((n_tokens < 4) ||
3338                                 parser_read_uint32(&pcp, tokens[1]) ||
3339                                 (pcp > 7) ||
3340                                 parser_read_uint32(&dei, tokens[2]) ||
3341                                 (dei > 1) ||
3342                                 parser_read_uint32(&vid, tokens[3]) ||
3343                                 (vid > 0xFFF))
3344                                 return 0;
3345
3346                         a->encap.vxlan.vlan.pcp = pcp;
3347                         a->encap.vxlan.vlan.dei = dei;
3348                         a->encap.vxlan.vlan.vid = vid;
3349
3350                         n_tokens -= 4;
3351                         tokens += 4;
3352                         n += 4;
3353                 }
3354
3355                 /* ipv4 <sa> <da> <dscp> <ttl>
3356                    | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> */
3357                 if (strcmp(tokens[0], "ipv4") == 0) {
3358                         struct in_addr sa, da;
3359                         uint8_t dscp, ttl;
3360
3361                         if ((n_tokens < 5) ||
3362                                 parse_ipv4_addr(tokens[1], &sa) ||
3363                                 parse_ipv4_addr(tokens[2], &da) ||
3364                                 parser_read_uint8(&dscp, tokens[3]) ||
3365                                 (dscp > 64) ||
3366                                 parser_read_uint8(&ttl, tokens[4]))
3367                                 return 0;
3368
3369                         a->encap.vxlan.ipv4.sa = rte_be_to_cpu_32(sa.s_addr);
3370                         a->encap.vxlan.ipv4.da = rte_be_to_cpu_32(da.s_addr);
3371                         a->encap.vxlan.ipv4.dscp = dscp;
3372                         a->encap.vxlan.ipv4.ttl = ttl;
3373
3374                         n_tokens -= 5;
3375                         tokens += 5;
3376                         n += 5;
3377                 } else if (strcmp(tokens[0], "ipv6") == 0) {
3378                         struct in6_addr sa, da;
3379                         uint32_t flow_label;
3380                         uint8_t dscp, hop_limit;
3381
3382                         if ((n_tokens < 6) ||
3383                                 parse_ipv6_addr(tokens[1], &sa) ||
3384                                 parse_ipv6_addr(tokens[2], &da) ||
3385                                 parser_read_uint32(&flow_label, tokens[3]) ||
3386                                 parser_read_uint8(&dscp, tokens[4]) ||
3387                                 (dscp > 64) ||
3388                                 parser_read_uint8(&hop_limit, tokens[5]))
3389                                 return 0;
3390
3391                         memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16);
3392                         memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16);
3393                         a->encap.vxlan.ipv6.flow_label = flow_label;
3394                         a->encap.vxlan.ipv6.dscp = dscp;
3395                         a->encap.vxlan.ipv6.hop_limit = hop_limit;
3396
3397                         n_tokens -= 6;
3398                         tokens += 6;
3399                         n += 6;
3400                 } else
3401                         return 0;
3402
3403                 /* udp <sp> <dp> */
3404                 if ((n_tokens < 3) ||
3405                         strcmp(tokens[0], "udp") ||
3406                         parser_read_uint16(&a->encap.vxlan.udp.sp, tokens[1]) ||
3407                         parser_read_uint16(&a->encap.vxlan.udp.dp, tokens[2]))
3408                         return 0;
3409
3410                 n_tokens -= 3;
3411                 tokens += 3;
3412                 n += 3;
3413
3414                 /* vxlan <vni> */
3415                 if ((n_tokens < 2) ||
3416                         strcmp(tokens[0], "vxlan") ||
3417                         parser_read_uint32(&a->encap.vxlan.vxlan.vni, tokens[1]) ||
3418                         (a->encap.vxlan.vxlan.vni > 0xFFFFFF))
3419                         return 0;
3420
3421                 n_tokens -= 2;
3422                 tokens += 2;
3423                 n += 2;
3424
3425                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN;
3426                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3427                 return 1 + n;
3428         }
3429
3430         return 0;
3431 }
3432
3433 static uint32_t
3434 parse_table_action_nat(char **tokens,
3435         uint32_t n_tokens,
3436         struct table_rule_action *a)
3437 {
3438         if ((n_tokens < 4) ||
3439                 strcmp(tokens[0], "nat"))
3440                 return 0;
3441
3442         if (strcmp(tokens[1], "ipv4") == 0) {
3443                 struct in_addr addr;
3444                 uint16_t port;
3445
3446                 if (parse_ipv4_addr(tokens[2], &addr) ||
3447                         parser_read_uint16(&port, tokens[3]))
3448                         return 0;
3449
3450                 a->nat.ip_version = 1;
3451                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3452                 a->nat.port = port;
3453                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3454                 return 4;
3455         }
3456
3457         if (strcmp(tokens[1], "ipv6") == 0) {
3458                 struct in6_addr addr;
3459                 uint16_t port;
3460
3461                 if (parse_ipv6_addr(tokens[2], &addr) ||
3462                         parser_read_uint16(&port, tokens[3]))
3463                         return 0;
3464
3465                 a->nat.ip_version = 0;
3466                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3467                 a->nat.port = port;
3468                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3469                 return 4;
3470         }
3471
3472         return 0;
3473 }
3474
3475 static uint32_t
3476 parse_table_action_ttl(char **tokens,
3477         uint32_t n_tokens,
3478         struct table_rule_action *a)
3479 {
3480         if ((n_tokens < 2) ||
3481                 strcmp(tokens[0], "ttl"))
3482                 return 0;
3483
3484         if (strcmp(tokens[1], "dec") == 0)
3485                 a->ttl.decrement = 1;
3486         else if (strcmp(tokens[1], "keep") == 0)
3487                 a->ttl.decrement = 0;
3488         else
3489                 return 0;
3490
3491         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
3492         return 2;
3493 }
3494
3495 static uint32_t
3496 parse_table_action_stats(char **tokens,
3497         uint32_t n_tokens,
3498         struct table_rule_action *a)
3499 {
3500         if ((n_tokens < 1) ||
3501                 strcmp(tokens[0], "stats"))
3502                 return 0;
3503
3504         a->stats.n_packets = 0;
3505         a->stats.n_bytes = 0;
3506         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
3507         return 1;
3508 }
3509
3510 static uint32_t
3511 parse_table_action_time(char **tokens,
3512         uint32_t n_tokens,
3513         struct table_rule_action *a)
3514 {
3515         if ((n_tokens < 1) ||
3516                 strcmp(tokens[0], "time"))
3517                 return 0;
3518
3519         a->time.time = rte_rdtsc();
3520         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
3521         return 1;
3522 }
3523
3524 static uint32_t
3525 parse_table_action(char **tokens,
3526         uint32_t n_tokens,
3527         char *out,
3528         size_t out_size,
3529         struct table_rule_action *a)
3530 {
3531         uint32_t n_tokens0 = n_tokens;
3532
3533         memset(a, 0, sizeof(*a));
3534
3535         if ((n_tokens < 2) ||
3536                 strcmp(tokens[0], "action"))
3537                 return 0;
3538
3539         tokens++;
3540         n_tokens--;
3541
3542         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
3543                 uint32_t n;
3544
3545                 n = parse_table_action_fwd(tokens, n_tokens, a);
3546                 if (n == 0) {
3547                         snprintf(out, out_size, MSG_ARG_INVALID,
3548                                 "action fwd");
3549                         return 0;
3550                 }
3551
3552                 tokens += n;
3553                 n_tokens -= n;
3554         }
3555
3556         if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
3557                 uint32_t n;
3558
3559                 n = parse_table_action_balance(tokens, n_tokens, a);
3560                 if (n == 0) {
3561                         snprintf(out, out_size, MSG_ARG_INVALID,
3562                                 "action balance");
3563                         return 0;
3564                 }
3565
3566                 tokens += n;
3567                 n_tokens -= n;
3568         }
3569
3570         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
3571                 uint32_t n;
3572
3573                 n = parse_table_action_meter(tokens, n_tokens, a);
3574                 if (n == 0) {
3575                         snprintf(out, out_size, MSG_ARG_INVALID,
3576                                 "action meter");
3577                         return 0;
3578                 }
3579
3580                 tokens += n;
3581                 n_tokens -= n;
3582         }
3583
3584         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
3585                 uint32_t n;
3586
3587                 n = parse_table_action_tm(tokens, n_tokens, a);
3588                 if (n == 0) {
3589                         snprintf(out, out_size, MSG_ARG_INVALID,
3590                                 "action tm");
3591                         return 0;
3592                 }
3593
3594                 tokens += n;
3595                 n_tokens -= n;
3596         }
3597
3598         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
3599                 uint32_t n;
3600
3601                 n = parse_table_action_encap(tokens, n_tokens, a);
3602                 if (n == 0) {
3603                         snprintf(out, out_size, MSG_ARG_INVALID,
3604                                 "action encap");
3605                         return 0;
3606                 }
3607
3608                 tokens += n;
3609                 n_tokens -= n;
3610         }
3611
3612         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
3613                 uint32_t n;
3614
3615                 n = parse_table_action_nat(tokens, n_tokens, a);
3616                 if (n == 0) {
3617                         snprintf(out, out_size, MSG_ARG_INVALID,
3618                                 "action nat");
3619                         return 0;
3620                 }
3621
3622                 tokens += n;
3623                 n_tokens -= n;
3624         }
3625
3626         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
3627                 uint32_t n;
3628
3629                 n = parse_table_action_ttl(tokens, n_tokens, a);
3630                 if (n == 0) {
3631                         snprintf(out, out_size, MSG_ARG_INVALID,
3632                                 "action ttl");
3633                         return 0;
3634                 }
3635
3636                 tokens += n;
3637                 n_tokens -= n;
3638         }
3639
3640         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
3641                 uint32_t n;
3642
3643                 n = parse_table_action_stats(tokens, n_tokens, a);
3644                 if (n == 0) {
3645                         snprintf(out, out_size, MSG_ARG_INVALID,
3646                                 "action stats");
3647                         return 0;
3648                 }
3649
3650                 tokens += n;
3651                 n_tokens -= n;
3652         }
3653
3654         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
3655                 uint32_t n;
3656
3657                 n = parse_table_action_time(tokens, n_tokens, a);
3658                 if (n == 0) {
3659                         snprintf(out, out_size, MSG_ARG_INVALID,
3660                                 "action time");
3661                         return 0;
3662                 }
3663
3664                 tokens += n;
3665                 n_tokens -= n;
3666         }
3667
3668         if (n_tokens0 - n_tokens == 1) {
3669                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3670                 return 0;
3671         }
3672
3673         return n_tokens0 - n_tokens;
3674 }
3675
3676
3677 static const char cmd_pipeline_table_rule_add_help[] =
3678 "pipeline <pipeline_name> table <table_id> rule add\n"
3679 "     match <match>\n"
3680 "     action <table_action>\n";
3681
3682 static void
3683 cmd_pipeline_table_rule_add(char **tokens,
3684         uint32_t n_tokens,
3685         char *out,
3686         size_t out_size)
3687 {
3688         struct table_rule_match m;
3689         struct table_rule_action a;
3690         char *pipeline_name;
3691         void *data;
3692         uint32_t table_id, t0, n_tokens_parsed;
3693         int status;
3694
3695         if (n_tokens < 8) {
3696                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3697                 return;
3698         }
3699
3700         pipeline_name = tokens[1];
3701
3702         if (strcmp(tokens[2], "table") != 0) {
3703                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3704                 return;
3705         }
3706
3707         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3708                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3709                 return;
3710         }
3711
3712         if (strcmp(tokens[4], "rule") != 0) {
3713                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3714                 return;
3715         }
3716
3717         if (strcmp(tokens[5], "add") != 0) {
3718                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3719                 return;
3720         }
3721
3722         t0 = 6;
3723
3724         /* match */
3725         n_tokens_parsed = parse_match(tokens + t0,
3726                 n_tokens - t0,
3727                 out,
3728                 out_size,
3729                 &m);
3730         if (n_tokens_parsed == 0)
3731                 return;
3732         t0 += n_tokens_parsed;
3733
3734         /* action */
3735         n_tokens_parsed = parse_table_action(tokens + t0,
3736                 n_tokens - t0,
3737                 out,
3738                 out_size,
3739                 &a);
3740         if (n_tokens_parsed == 0)
3741                 return;
3742         t0 += n_tokens_parsed;
3743
3744         if (t0 != n_tokens) {
3745                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
3746                 return;
3747         }
3748
3749         status = pipeline_table_rule_add(pipeline_name, table_id,
3750                 &m, &a, &data);
3751         if (status) {
3752                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3753                 return;
3754         }
3755 }
3756
3757
3758 static const char cmd_pipeline_table_rule_add_default_help[] =
3759 "pipeline <pipeline_name> table <table_id> rule add\n"
3760 "     match\n"
3761 "        default\n"
3762 "     action\n"
3763 "        fwd\n"
3764 "           drop\n"
3765 "           | port <port_id>\n"
3766 "           | meta\n"
3767 "           | table <table_id>\n";
3768
3769 static void
3770 cmd_pipeline_table_rule_add_default(char **tokens,
3771         uint32_t n_tokens,
3772         char *out,
3773         size_t out_size)
3774 {
3775         struct table_rule_action action;
3776         void *data;
3777         char *pipeline_name;
3778         uint32_t table_id;
3779         int status;
3780
3781         if ((n_tokens != 11) && (n_tokens != 12)) {
3782                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3783                 return;
3784         }
3785
3786         pipeline_name = tokens[1];
3787
3788         if (strcmp(tokens[2], "table") != 0) {
3789                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3790                 return;
3791         }
3792
3793         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3794                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3795                 return;
3796         }
3797
3798         if (strcmp(tokens[4], "rule") != 0) {
3799                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3800                 return;
3801         }
3802
3803         if (strcmp(tokens[5], "add") != 0) {
3804                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3805                 return;
3806         }
3807
3808         if (strcmp(tokens[6], "match") != 0) {
3809                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3810                 return;
3811         }
3812
3813         if (strcmp(tokens[7], "default") != 0) {
3814                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3815                 return;
3816         }
3817
3818         if (strcmp(tokens[8], "action") != 0) {
3819                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3820                 return;
3821         }
3822
3823         if (strcmp(tokens[9], "fwd") != 0) {
3824                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
3825                 return;
3826         }
3827
3828         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
3829
3830         if (strcmp(tokens[10], "drop") == 0) {
3831                 if (n_tokens != 11) {
3832                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3833                         return;
3834                 }
3835
3836                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
3837         } else if (strcmp(tokens[10], "port") == 0) {
3838                 uint32_t id;
3839
3840                 if (n_tokens != 12) {
3841                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3842                         return;
3843                 }
3844
3845                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3846                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
3847                         return;
3848                 }
3849
3850                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
3851                 action.fwd.id = id;
3852         } else if (strcmp(tokens[10], "meta") == 0) {
3853                 if (n_tokens != 11) {
3854                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3855                         return;
3856                 }
3857
3858                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3859         } else if (strcmp(tokens[10], "table") == 0) {
3860                 uint32_t id;
3861
3862                 if (n_tokens != 12) {
3863                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3864                         return;
3865                 }
3866
3867                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3868                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3869                         return;
3870                 }
3871
3872                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
3873                 action.fwd.id = id;
3874         } else {
3875                 snprintf(out, out_size, MSG_ARG_INVALID,
3876                         "drop or port or meta or table");
3877                 return;
3878         }
3879
3880         status = pipeline_table_rule_add_default(pipeline_name,
3881                 table_id,
3882                 &action,
3883                 &data);
3884         if (status) {
3885                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3886                 return;
3887         }
3888 }
3889
3890
3891 static const char cmd_pipeline_table_rule_add_bulk_help[] =
3892 "pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>\n"
3893 "\n"
3894 "  File <file_name>:\n"
3895 "  - line format: match <match> action <action>\n";
3896
3897 static int
3898 cli_rule_file_process(const char *file_name,
3899         size_t line_len_max,
3900         struct table_rule_match *m,
3901         struct table_rule_action *a,
3902         uint32_t *n_rules,
3903         uint32_t *line_number,
3904         char *out,
3905         size_t out_size);
3906
3907 static void
3908 cmd_pipeline_table_rule_add_bulk(char **tokens,
3909         uint32_t n_tokens,
3910         char *out,
3911         size_t out_size)
3912 {
3913         struct table_rule_match *match;
3914         struct table_rule_action *action;
3915         void **data;
3916         char *pipeline_name, *file_name;
3917         uint32_t table_id, n_rules, n_rules_parsed, line_number;
3918         int status;
3919
3920         if (n_tokens != 9) {
3921                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3922                 return;
3923         }
3924
3925         pipeline_name = tokens[1];
3926
3927         if (strcmp(tokens[2], "table") != 0) {
3928                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3929                 return;
3930         }
3931
3932         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3933                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3934                 return;
3935         }
3936
3937         if (strcmp(tokens[4], "rule") != 0) {
3938                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3939                 return;
3940         }
3941
3942         if (strcmp(tokens[5], "add") != 0) {
3943                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3944                 return;
3945         }
3946
3947         if (strcmp(tokens[6], "bulk") != 0) {
3948                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
3949                 return;
3950         }
3951
3952         file_name = tokens[7];
3953
3954         if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
3955                 (n_rules == 0)) {
3956                 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
3957                 return;
3958         }
3959
3960         /* Memory allocation. */
3961         match = calloc(n_rules, sizeof(struct table_rule_match));
3962         action = calloc(n_rules, sizeof(struct table_rule_action));
3963         data = calloc(n_rules, sizeof(void *));
3964         if ((match == NULL) || (action == NULL) || (data == NULL)) {
3965                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
3966                 free(data);
3967                 free(action);
3968                 free(match);
3969                 return;
3970         }
3971
3972         /* Load rule file */
3973         n_rules_parsed = n_rules;
3974         status = cli_rule_file_process(file_name,
3975                 1024,
3976                 match,
3977                 action,
3978                 &n_rules_parsed,
3979                 &line_number,
3980                 out,
3981                 out_size);
3982         if (status) {
3983                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
3984                 free(data);
3985                 free(action);
3986                 free(match);
3987                 return;
3988         }
3989         if (n_rules_parsed != n_rules) {
3990                 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
3991                 free(data);
3992                 free(action);
3993                 free(match);
3994                 return;
3995         }
3996
3997         /* Rule bulk add */
3998         status = pipeline_table_rule_add_bulk(pipeline_name,
3999                 table_id,
4000                 match,
4001                 action,
4002                 data,
4003                 &n_rules);
4004         if (status) {
4005                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4006                 free(data);
4007                 free(action);
4008                 free(match);
4009                 return;
4010         }
4011
4012         /* Memory free */
4013         free(data);
4014         free(action);
4015         free(match);
4016 }
4017
4018
4019 static const char cmd_pipeline_table_rule_delete_help[] =
4020 "pipeline <pipeline_name> table <table_id> rule delete\n"
4021 "     match <match>\n";
4022
4023 static void
4024 cmd_pipeline_table_rule_delete(char **tokens,
4025         uint32_t n_tokens,
4026         char *out,
4027         size_t out_size)
4028 {
4029         struct table_rule_match m;
4030         char *pipeline_name;
4031         uint32_t table_id, n_tokens_parsed, t0;
4032         int status;
4033
4034         if (n_tokens < 8) {
4035                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4036                 return;
4037         }
4038
4039         pipeline_name = tokens[1];
4040
4041         if (strcmp(tokens[2], "table") != 0) {
4042                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4043                 return;
4044         }
4045
4046         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4047                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4048                 return;
4049         }
4050
4051         if (strcmp(tokens[4], "rule") != 0) {
4052                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4053                 return;
4054         }
4055
4056         if (strcmp(tokens[5], "delete") != 0) {
4057                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4058                 return;
4059         }
4060
4061         t0 = 6;
4062
4063         /* match */
4064         n_tokens_parsed = parse_match(tokens + t0,
4065                 n_tokens - t0,
4066                 out,
4067                 out_size,
4068                 &m);
4069         if (n_tokens_parsed == 0)
4070                 return;
4071         t0 += n_tokens_parsed;
4072
4073         if (n_tokens != t0) {
4074                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4075                 return;
4076         }
4077
4078         status = pipeline_table_rule_delete(pipeline_name,
4079                 table_id,
4080                 &m);
4081         if (status) {
4082                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4083                 return;
4084         }
4085 }
4086
4087
4088 static const char cmd_pipeline_table_rule_delete_default_help[] =
4089 "pipeline <pipeline_name> table <table_id> rule delete\n"
4090 "     match\n"
4091 "        default\n";
4092
4093 static void
4094 cmd_pipeline_table_rule_delete_default(char **tokens,
4095         uint32_t n_tokens,
4096         char *out,
4097         size_t out_size)
4098 {
4099         char *pipeline_name;
4100         uint32_t table_id;
4101         int status;
4102
4103         if (n_tokens != 8) {
4104                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4105                 return;
4106         }
4107
4108         pipeline_name = tokens[1];
4109
4110         if (strcmp(tokens[2], "table") != 0) {
4111                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4112                 return;
4113         }
4114
4115         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4116                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4117                 return;
4118         }
4119
4120         if (strcmp(tokens[4], "rule") != 0) {
4121                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4122                 return;
4123         }
4124
4125         if (strcmp(tokens[5], "delete") != 0) {
4126                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4127                 return;
4128         }
4129
4130         if (strcmp(tokens[6], "match") != 0) {
4131                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
4132                 return;
4133         }
4134
4135         if (strcmp(tokens[7], "default") != 0) {
4136                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
4137                 return;
4138         }
4139
4140         status = pipeline_table_rule_delete_default(pipeline_name,
4141                 table_id);
4142         if (status) {
4143                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4144                 return;
4145         }
4146 }
4147
4148
4149 static const char cmd_pipeline_table_rule_stats_read_help[] =
4150 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n";
4151
4152 static void
4153 cmd_pipeline_table_rule_stats_read(char **tokens,
4154         uint32_t n_tokens __rte_unused,
4155         char *out,
4156         size_t out_size)
4157 {
4158         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4159 }
4160
4161
4162 static const char cmd_pipeline_table_meter_profile_add_help[] =
4163 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n"
4164 "   add srtcm cir <cir> cbs <cbs> ebs <ebs>\n"
4165 "   | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
4166
4167 static void
4168 cmd_pipeline_table_meter_profile_add(char **tokens,
4169         uint32_t n_tokens,
4170         char *out,
4171         size_t out_size)
4172 {
4173         struct rte_table_action_meter_profile p;
4174         char *pipeline_name;
4175         uint32_t table_id, meter_profile_id;
4176         int status;
4177
4178         if (n_tokens < 9) {
4179                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4180                 return;
4181         }
4182
4183         pipeline_name = tokens[1];
4184
4185         if (strcmp(tokens[2], "table") != 0) {
4186                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4187                 return;
4188         }
4189
4190         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4191                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4192                 return;
4193         }
4194
4195         if (strcmp(tokens[4], "meter") != 0) {
4196                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4197                 return;
4198         }
4199
4200         if (strcmp(tokens[5], "profile") != 0) {
4201                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4202                 return;
4203         }
4204
4205         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4206                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4207                 return;
4208         }
4209
4210         if (strcmp(tokens[7], "add") != 0) {
4211                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4212                 return;
4213         }
4214
4215         if (strcmp(tokens[8], "srtcm") == 0) {
4216                 if (n_tokens != 15) {
4217                         snprintf(out, out_size, MSG_ARG_MISMATCH,
4218                                 tokens[0]);
4219                         return;
4220                 }
4221
4222                 p.alg = RTE_TABLE_ACTION_METER_SRTCM;
4223
4224                 if (strcmp(tokens[9], "cir") != 0) {
4225                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4226                         return;
4227                 }
4228
4229                 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
4230                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4231                         return;
4232                 }
4233
4234                 if (strcmp(tokens[11], "cbs") != 0) {
4235                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4236                         return;
4237                 }
4238
4239                 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
4240                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4241                         return;
4242                 }
4243
4244                 if (strcmp(tokens[13], "ebs") != 0) {
4245                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
4246                         return;
4247                 }
4248
4249                 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
4250                         snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
4251                         return;
4252                 }
4253         } else if (strcmp(tokens[8], "trtcm") == 0) {
4254                 if (n_tokens != 17) {
4255                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4256                         return;
4257                 }
4258
4259                 p.alg = RTE_TABLE_ACTION_METER_TRTCM;
4260
4261                 if (strcmp(tokens[9], "cir") != 0) {
4262                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4263                         return;
4264                 }
4265
4266                 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
4267                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4268                         return;
4269                 }
4270
4271                 if (strcmp(tokens[11], "pir") != 0) {
4272                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
4273                         return;
4274                 }
4275
4276                 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
4277                         snprintf(out, out_size, MSG_ARG_INVALID, "pir");
4278                         return;
4279                 }
4280                 if (strcmp(tokens[13], "cbs") != 0) {
4281                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4282                         return;
4283                 }
4284
4285                 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
4286                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4287                         return;
4288                 }
4289
4290                 if (strcmp(tokens[15], "pbs") != 0) {
4291                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
4292                         return;
4293                 }
4294
4295                 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
4296                         snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
4297                         return;
4298                 }
4299         } else {
4300                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4301                 return;
4302         }
4303
4304         status = pipeline_table_mtr_profile_add(pipeline_name,
4305                 table_id,
4306                 meter_profile_id,
4307                 &p);
4308         if (status) {
4309                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4310                 return;
4311         }
4312 }
4313
4314
4315 static const char cmd_pipeline_table_meter_profile_delete_help[] =
4316 "pipeline <pipeline_name> table <table_id>\n"
4317 "   meter profile <meter_profile_id> delete\n";
4318
4319 static void
4320 cmd_pipeline_table_meter_profile_delete(char **tokens,
4321         uint32_t n_tokens,
4322         char *out,
4323         size_t out_size)
4324 {
4325         char *pipeline_name;
4326         uint32_t table_id, meter_profile_id;
4327         int status;
4328
4329         if (n_tokens != 8) {
4330                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4331                 return;
4332         }
4333
4334         pipeline_name = tokens[1];
4335
4336         if (strcmp(tokens[2], "table") != 0) {
4337                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4338                 return;
4339         }
4340
4341         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4342                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4343                 return;
4344         }
4345
4346         if (strcmp(tokens[4], "meter") != 0) {
4347                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4348                 return;
4349         }
4350
4351         if (strcmp(tokens[5], "profile") != 0) {
4352                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4353                 return;
4354         }
4355
4356         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4357                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4358                 return;
4359         }
4360
4361         if (strcmp(tokens[7], "delete") != 0) {
4362                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4363                 return;
4364         }
4365
4366         status = pipeline_table_mtr_profile_delete(pipeline_name,
4367                 table_id,
4368                 meter_profile_id);
4369         if (status) {
4370                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4371                 return;
4372         }
4373 }
4374
4375
4376 static const char cmd_pipeline_table_rule_meter_read_help[] =
4377 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n";
4378
4379 static void
4380 cmd_pipeline_table_rule_meter_read(char **tokens,
4381         uint32_t n_tokens __rte_unused,
4382         char *out,
4383         size_t out_size)
4384 {
4385         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4386 }
4387
4388
4389 static const char cmd_pipeline_table_dscp_help[] =
4390 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n"
4391 "\n"
4392 " File <file_name>:\n"
4393 "   - exactly 64 lines\n"
4394 "   - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n";
4395
4396 static int
4397 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
4398         const char *file_name,
4399         uint32_t *line_number)
4400 {
4401         FILE *f = NULL;
4402         uint32_t dscp, l;
4403
4404         /* Check input arguments */
4405         if ((dscp_table == NULL) ||
4406                 (file_name == NULL) ||
4407                 (line_number == NULL)) {
4408                 if (line_number)
4409                         *line_number = 0;
4410                 return -EINVAL;
4411         }
4412
4413         /* Open input file */
4414         f = fopen(file_name, "r");
4415         if (f == NULL) {
4416                 *line_number = 0;
4417                 return -EINVAL;
4418         }
4419
4420         /* Read file */
4421         for (dscp = 0, l = 1; ; l++) {
4422                 char line[64];
4423                 char *tokens[3];
4424                 enum rte_meter_color color;
4425                 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
4426
4427                 if (fgets(line, sizeof(line), f) == NULL)
4428                         break;
4429
4430                 if (is_comment(line))
4431                         continue;
4432
4433                 if (parse_tokenize_string(line, tokens, &n_tokens)) {
4434                         *line_number = l;
4435                         fclose(f);
4436                         return -EINVAL;
4437                 }
4438
4439                 if (n_tokens == 0)
4440                         continue;
4441
4442                 if ((dscp >= RTE_DIM(dscp_table->entry)) ||
4443                         (n_tokens != RTE_DIM(tokens)) ||
4444                         parser_read_uint32(&tc_id, tokens[0]) ||
4445                         (tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
4446                         parser_read_uint32(&tc_queue_id, tokens[1]) ||
4447                         (tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
4448                         (strlen(tokens[2]) != 1)) {
4449                         *line_number = l;
4450                         fclose(f);
4451                         return -EINVAL;
4452                 }
4453
4454                 switch (tokens[2][0]) {
4455                 case 'g':
4456                 case 'G':
4457                         color = e_RTE_METER_GREEN;
4458                         break;
4459
4460                 case 'y':
4461                 case 'Y':
4462                         color = e_RTE_METER_YELLOW;
4463                         break;
4464
4465                 case 'r':
4466                 case 'R':
4467                         color = e_RTE_METER_RED;
4468                         break;
4469
4470                 default:
4471                         *line_number = l;
4472                         fclose(f);
4473                         return -EINVAL;
4474                 }
4475
4476                 dscp_table->entry[dscp].tc_id = tc_id;
4477                 dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
4478                 dscp_table->entry[dscp].color = color;
4479                 dscp++;
4480         }
4481
4482         /* Close file */
4483         fclose(f);
4484         return 0;
4485 }
4486
4487 static void
4488 cmd_pipeline_table_dscp(char **tokens,
4489         uint32_t n_tokens,
4490         char *out,
4491         size_t out_size)
4492 {
4493         struct rte_table_action_dscp_table dscp_table;
4494         char *pipeline_name, *file_name;
4495         uint32_t table_id, line_number;
4496         int status;
4497
4498         if (n_tokens != 6) {
4499                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4500                 return;
4501         }
4502
4503         pipeline_name = tokens[1];
4504
4505         if (strcmp(tokens[2], "table") != 0) {
4506                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4507                 return;
4508         }
4509
4510         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4511                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4512                 return;
4513         }
4514
4515         if (strcmp(tokens[4], "dscp") != 0) {
4516                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
4517                 return;
4518         }
4519
4520         file_name = tokens[5];
4521
4522         status = load_dscp_table(&dscp_table, file_name, &line_number);
4523         if (status) {
4524                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4525                 return;
4526         }
4527
4528         status = pipeline_table_dscp_table_update(pipeline_name,
4529                 table_id,
4530                 UINT64_MAX,
4531                 &dscp_table);
4532         if (status) {
4533                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4534                 return;
4535         }
4536 }
4537
4538
4539 static const char cmd_pipeline_table_rule_ttl_read_help[] =
4540 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n";
4541
4542 static void
4543 cmd_pipeline_table_rule_ttl_read(char **tokens,
4544         uint32_t n_tokens __rte_unused,
4545         char *out,
4546         size_t out_size)
4547 {
4548         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4549 }
4550
4551
4552 static const char cmd_thread_pipeline_enable_help[] =
4553 "thread <thread_id> pipeline <pipeline_name> enable\n";
4554
4555 static void
4556 cmd_thread_pipeline_enable(char **tokens,
4557         uint32_t n_tokens,
4558         char *out,
4559         size_t out_size)
4560 {
4561         char *pipeline_name;
4562         uint32_t thread_id;
4563         int status;
4564
4565         if (n_tokens != 5) {
4566                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4567                 return;
4568         }
4569
4570         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4571                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4572                 return;
4573         }
4574
4575         if (strcmp(tokens[2], "pipeline") != 0) {
4576                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4577                 return;
4578         }
4579
4580         pipeline_name = tokens[3];
4581
4582         if (strcmp(tokens[4], "enable") != 0) {
4583                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
4584                 return;
4585         }
4586
4587         status = thread_pipeline_enable(thread_id, pipeline_name);
4588         if (status) {
4589                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
4590                 return;
4591         }
4592 }
4593
4594
4595 static const char cmd_thread_pipeline_disable_help[] =
4596 "thread <thread_id> pipeline <pipeline_name> disable\n";
4597
4598 static void
4599 cmd_thread_pipeline_disable(char **tokens,
4600         uint32_t n_tokens,
4601         char *out,
4602         size_t out_size)
4603 {
4604         char *pipeline_name;
4605         uint32_t thread_id;
4606         int status;
4607
4608         if (n_tokens != 5) {
4609                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4610                 return;
4611         }
4612
4613         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4614                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4615                 return;
4616         }
4617
4618         if (strcmp(tokens[2], "pipeline") != 0) {
4619                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4620                 return;
4621         }
4622
4623         pipeline_name = tokens[3];
4624
4625         if (strcmp(tokens[4], "disable") != 0) {
4626                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
4627                 return;
4628         }
4629
4630         status = thread_pipeline_disable(thread_id, pipeline_name);
4631         if (status) {
4632                 snprintf(out, out_size, MSG_CMD_FAIL,
4633                         "thread pipeline disable");
4634                 return;
4635         }
4636 }
4637
4638 static void
4639 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
4640 {
4641         tokens++;
4642         n_tokens--;
4643
4644         if (n_tokens == 0) {
4645                 snprintf(out, out_size,
4646                         "Type 'help <command>' for details on each command.\n\n"
4647                         "List of commands:\n"
4648                         "\tmempool\n"
4649                         "\tlink\n"
4650                         "\tswq\n"
4651                         "\ttmgr subport profile\n"
4652                         "\ttmgr pipe profile\n"
4653                         "\ttmgr\n"
4654                         "\ttmgr subport\n"
4655                         "\ttmgr subport pipe\n"
4656                         "\ttap\n"
4657                         "\tkni\n"
4658                         "\tport in action profile\n"
4659                         "\ttable action profile\n"
4660                         "\tpipeline\n"
4661                         "\tpipeline port in\n"
4662                         "\tpipeline port out\n"
4663                         "\tpipeline table\n"
4664                         "\tpipeline port in table\n"
4665                         "\tpipeline port in stats\n"
4666                         "\tpipeline port in enable\n"
4667                         "\tpipeline port in disable\n"
4668                         "\tpipeline port out stats\n"
4669                         "\tpipeline table stats\n"
4670                         "\tpipeline table rule add\n"
4671                         "\tpipeline table rule add default\n"
4672                         "\tpipeline table rule add bulk\n"
4673                         "\tpipeline table rule delete\n"
4674                         "\tpipeline table rule delete default\n"
4675                         "\tpipeline table rule stats read\n"
4676                         "\tpipeline table meter profile add\n"
4677                         "\tpipeline table meter profile delete\n"
4678                         "\tpipeline table rule meter read\n"
4679                         "\tpipeline table dscp\n"
4680                         "\tpipeline table rule ttl read\n"
4681                         "\tthread pipeline enable\n"
4682                         "\tthread pipeline disable\n\n");
4683                 return;
4684         }
4685
4686         if (strcmp(tokens[0], "mempool") == 0) {
4687                 snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
4688                 return;
4689         }
4690
4691         if (strcmp(tokens[0], "link") == 0) {
4692                 snprintf(out, out_size, "\n%s\n", cmd_link_help);
4693                 return;
4694         }
4695
4696         if (strcmp(tokens[0], "swq") == 0) {
4697                 snprintf(out, out_size, "\n%s\n", cmd_swq_help);
4698                 return;
4699         }
4700
4701         if (strcmp(tokens[0], "tmgr") == 0) {
4702                 if (n_tokens == 1) {
4703                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_help);
4704                         return;
4705                 }
4706
4707                 if ((n_tokens == 2) &&
4708                         (strcmp(tokens[1], "subport")) == 0) {
4709                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help);
4710                         return;
4711                 }
4712
4713                 if ((n_tokens == 3) &&
4714                         (strcmp(tokens[1], "subport") == 0) &&
4715                         (strcmp(tokens[2], "profile") == 0)) {
4716                         snprintf(out, out_size, "\n%s\n",
4717                                 cmd_tmgr_subport_profile_help);
4718                         return;
4719                 }
4720
4721                 if ((n_tokens == 3) &&
4722                         (strcmp(tokens[1], "subport") == 0) &&
4723                         (strcmp(tokens[2], "pipe") == 0)) {
4724                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help);
4725                         return;
4726                 }
4727
4728                 if ((n_tokens == 3) &&
4729                         (strcmp(tokens[1], "pipe") == 0) &&
4730                         (strcmp(tokens[2], "profile") == 0)) {
4731                         snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help);
4732                         return;
4733                 }
4734         }
4735
4736         if (strcmp(tokens[0], "tap") == 0) {
4737                 snprintf(out, out_size, "\n%s\n", cmd_tap_help);
4738                 return;
4739         }
4740
4741         if (strcmp(tokens[0], "kni") == 0) {
4742                 snprintf(out, out_size, "\n%s\n", cmd_kni_help);
4743                 return;
4744         }
4745
4746         if ((n_tokens == 4) &&
4747                 (strcmp(tokens[0], "port") == 0) &&
4748                 (strcmp(tokens[1], "in") == 0) &&
4749                 (strcmp(tokens[2], "action") == 0) &&
4750                 (strcmp(tokens[3], "profile") == 0)) {
4751                 snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help);
4752                 return;
4753         }
4754
4755         if ((n_tokens == 3) &&
4756                 (strcmp(tokens[0], "table") == 0) &&
4757                 (strcmp(tokens[1], "action") == 0) &&
4758                 (strcmp(tokens[2], "profile") == 0)) {
4759                 snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help);
4760                 return;
4761         }
4762
4763         if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) {
4764                 snprintf(out, out_size, "\n%s\n", cmd_pipeline_help);
4765                 return;
4766         }
4767
4768         if ((strcmp(tokens[0], "pipeline") == 0) &&
4769                 (strcmp(tokens[1], "port") == 0)) {
4770                 if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) {
4771                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help);
4772                         return;
4773                 }
4774
4775                 if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) {
4776                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help);
4777                         return;
4778                 }
4779
4780                 if ((n_tokens == 4) &&
4781                         (strcmp(tokens[2], "in") == 0) &&
4782                         (strcmp(tokens[3], "table") == 0)) {
4783                         snprintf(out, out_size, "\n%s\n",
4784                                 cmd_pipeline_port_in_table_help);
4785                         return;
4786                 }
4787
4788                 if ((n_tokens == 4) &&
4789                         (strcmp(tokens[2], "in") == 0) &&
4790                         (strcmp(tokens[3], "stats") == 0)) {
4791                         snprintf(out, out_size, "\n%s\n",
4792                                 cmd_pipeline_port_in_stats_help);
4793                         return;
4794                 }
4795
4796                 if ((n_tokens == 4) &&
4797                         (strcmp(tokens[2], "in") == 0) &&
4798                         (strcmp(tokens[3], "enable") == 0)) {
4799                         snprintf(out, out_size, "\n%s\n",
4800                                 cmd_pipeline_port_in_enable_help);
4801                         return;
4802                 }
4803
4804                 if ((n_tokens == 4) &&
4805                         (strcmp(tokens[2], "in") == 0) &&
4806                         (strcmp(tokens[3], "disable") == 0)) {
4807                         snprintf(out, out_size, "\n%s\n",
4808                                 cmd_pipeline_port_in_disable_help);
4809                         return;
4810                 }
4811
4812                 if ((n_tokens == 4) &&
4813                         (strcmp(tokens[2], "out") == 0) &&
4814                         (strcmp(tokens[3], "stats") == 0)) {
4815                         snprintf(out, out_size, "\n%s\n",
4816                                 cmd_pipeline_port_out_stats_help);
4817                         return;
4818                 }
4819         }
4820
4821         if ((strcmp(tokens[0], "pipeline") == 0) &&
4822                 (strcmp(tokens[1], "table") == 0)) {
4823                 if (n_tokens == 2) {
4824                         snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help);
4825                         return;
4826                 }
4827
4828                 if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) {
4829                         snprintf(out, out_size, "\n%s\n",
4830                                 cmd_pipeline_table_stats_help);
4831                         return;
4832                 }
4833
4834                 if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) {
4835                         snprintf(out, out_size, "\n%s\n",
4836                                 cmd_pipeline_table_dscp_help);
4837                         return;
4838                 }
4839
4840                 if ((n_tokens == 4) &&
4841                         (strcmp(tokens[2], "rule") == 0) &&
4842                         (strcmp(tokens[3], "add") == 0)) {
4843                         snprintf(out, out_size, "\n%s\n",
4844                                 cmd_pipeline_table_rule_add_help);
4845                         return;
4846                 }
4847
4848                 if ((n_tokens == 5) &&
4849                         (strcmp(tokens[2], "rule") == 0) &&
4850                         (strcmp(tokens[3], "add") == 0) &&
4851                         (strcmp(tokens[4], "default") == 0)) {
4852                         snprintf(out, out_size, "\n%s\n",
4853                                 cmd_pipeline_table_rule_add_default_help);
4854                         return;
4855                 }
4856
4857                 if ((n_tokens == 5) &&
4858                         (strcmp(tokens[2], "rule") == 0) &&
4859                         (strcmp(tokens[3], "add") == 0) &&
4860                         (strcmp(tokens[4], "bulk") == 0)) {
4861                         snprintf(out, out_size, "\n%s\n",
4862                                 cmd_pipeline_table_rule_add_bulk_help);
4863                         return;
4864                 }
4865
4866                 if ((n_tokens == 4) &&
4867                         (strcmp(tokens[2], "rule") == 0) &&
4868                         (strcmp(tokens[3], "delete") == 0)) {
4869                         snprintf(out, out_size, "\n%s\n",
4870                                 cmd_pipeline_table_rule_delete_help);
4871                         return;
4872                 }
4873
4874                 if ((n_tokens == 5) &&
4875                         (strcmp(tokens[2], "rule") == 0) &&
4876                         (strcmp(tokens[3], "delete") == 0) &&
4877                         (strcmp(tokens[4], "default") == 0)) {
4878                         snprintf(out, out_size, "\n%s\n",
4879                                 cmd_pipeline_table_rule_delete_default_help);
4880                         return;
4881                 }
4882
4883                 if ((n_tokens == 5) &&
4884                         (strcmp(tokens[2], "rule") == 0) &&
4885                         (strcmp(tokens[3], "stats") == 0) &&
4886                         (strcmp(tokens[4], "read") == 0)) {
4887                         snprintf(out, out_size, "\n%s\n",
4888                                 cmd_pipeline_table_rule_stats_read_help);
4889                         return;
4890                 }
4891
4892                 if ((n_tokens == 5) &&
4893                         (strcmp(tokens[2], "meter") == 0) &&
4894                         (strcmp(tokens[3], "profile") == 0) &&
4895                         (strcmp(tokens[4], "add") == 0)) {
4896                         snprintf(out, out_size, "\n%s\n",
4897                                 cmd_pipeline_table_meter_profile_add_help);
4898                         return;
4899                 }
4900
4901                 if ((n_tokens == 5) &&
4902                         (strcmp(tokens[2], "meter") == 0) &&
4903                         (strcmp(tokens[3], "profile") == 0) &&
4904                         (strcmp(tokens[4], "delete") == 0)) {
4905                         snprintf(out, out_size, "\n%s\n",
4906                                 cmd_pipeline_table_meter_profile_delete_help);
4907                         return;
4908                 }
4909
4910                 if ((n_tokens == 5) &&
4911                         (strcmp(tokens[2], "rule") == 0) &&
4912                         (strcmp(tokens[3], "meter") == 0) &&
4913                         (strcmp(tokens[4], "read") == 0)) {
4914                         snprintf(out, out_size, "\n%s\n",
4915                                 cmd_pipeline_table_rule_meter_read_help);
4916                         return;
4917                 }
4918
4919                 if ((n_tokens == 5) &&
4920                         (strcmp(tokens[2], "rule") == 0) &&
4921                         (strcmp(tokens[3], "ttl") == 0) &&
4922                         (strcmp(tokens[4], "read") == 0)) {
4923                         snprintf(out, out_size, "\n%s\n",
4924                                 cmd_pipeline_table_rule_ttl_read_help);
4925                         return;
4926                 }
4927         }
4928
4929         if ((n_tokens == 3) &&
4930                 (strcmp(tokens[0], "thread") == 0) &&
4931                 (strcmp(tokens[1], "pipeline") == 0)) {
4932                 if (strcmp(tokens[2], "enable") == 0) {
4933                         snprintf(out, out_size, "\n%s\n",
4934                                 cmd_thread_pipeline_enable_help);
4935                         return;
4936                 }
4937
4938                 if (strcmp(tokens[2], "disable") == 0) {
4939                         snprintf(out, out_size, "\n%s\n",
4940                                 cmd_thread_pipeline_disable_help);
4941                         return;
4942                 }
4943         }
4944
4945         snprintf(out, out_size, "Invalid command\n");
4946 }
4947
4948 void
4949 cli_process(char *in, char *out, size_t out_size)
4950 {
4951         char *tokens[CMD_MAX_TOKENS];
4952         uint32_t n_tokens = RTE_DIM(tokens);
4953         int status;
4954
4955         if (is_comment(in))
4956                 return;
4957
4958         status = parse_tokenize_string(in, tokens, &n_tokens);
4959         if (status) {
4960                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
4961                 return;
4962         }
4963
4964         if (n_tokens == 0)
4965                 return;
4966
4967         if (strcmp(tokens[0], "help") == 0) {
4968                 cmd_help(tokens, n_tokens, out, out_size);
4969                 return;
4970         }
4971
4972         if (strcmp(tokens[0], "mempool") == 0) {
4973                 cmd_mempool(tokens, n_tokens, out, out_size);
4974                 return;
4975         }
4976
4977         if (strcmp(tokens[0], "link") == 0) {
4978                 if (strcmp(tokens[1], "show") == 0) {
4979                         cmd_link_show(tokens, n_tokens, out, out_size);
4980                         return;
4981                 }
4982
4983                 cmd_link(tokens, n_tokens, out, out_size);
4984                 return;
4985         }
4986
4987         if (strcmp(tokens[0], "swq") == 0) {
4988                 cmd_swq(tokens, n_tokens, out, out_size);
4989                 return;
4990         }
4991
4992         if (strcmp(tokens[0], "tmgr") == 0) {
4993                 if ((n_tokens >= 3) &&
4994                         (strcmp(tokens[1], "subport") == 0) &&
4995                         (strcmp(tokens[2], "profile") == 0)) {
4996                         cmd_tmgr_subport_profile(tokens, n_tokens,
4997                                 out, out_size);
4998                         return;
4999                 }
5000
5001                 if ((n_tokens >= 3) &&
5002                         (strcmp(tokens[1], "pipe") == 0) &&
5003                         (strcmp(tokens[2], "profile") == 0)) {
5004                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
5005                         return;
5006                 }
5007
5008                 if ((n_tokens >= 5) &&
5009                         (strcmp(tokens[2], "subport") == 0) &&
5010                         (strcmp(tokens[4], "profile") == 0)) {
5011                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
5012                         return;
5013                 }
5014
5015                 if ((n_tokens >= 5) &&
5016                         (strcmp(tokens[2], "subport") == 0) &&
5017                         (strcmp(tokens[4], "pipe") == 0)) {
5018                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
5019                         return;
5020                 }
5021
5022                 cmd_tmgr(tokens, n_tokens, out, out_size);
5023                 return;
5024         }
5025
5026         if (strcmp(tokens[0], "tap") == 0) {
5027                 cmd_tap(tokens, n_tokens, out, out_size);
5028                 return;
5029         }
5030
5031         if (strcmp(tokens[0], "kni") == 0) {
5032                 cmd_kni(tokens, n_tokens, out, out_size);
5033                 return;
5034         }
5035
5036         if (strcmp(tokens[0], "port") == 0) {
5037                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
5038                 return;
5039         }
5040
5041         if (strcmp(tokens[0], "table") == 0) {
5042                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
5043                 return;
5044         }
5045
5046         if (strcmp(tokens[0], "pipeline") == 0) {
5047                 if ((n_tokens >= 3) &&
5048                         (strcmp(tokens[2], "period") == 0)) {
5049                         cmd_pipeline(tokens, n_tokens, out, out_size);
5050                         return;
5051                 }
5052
5053                 if ((n_tokens >= 5) &&
5054                         (strcmp(tokens[2], "port") == 0) &&
5055                         (strcmp(tokens[3], "in") == 0) &&
5056                         (strcmp(tokens[4], "bsz") == 0)) {
5057                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
5058                         return;
5059                 }
5060
5061                 if ((n_tokens >= 5) &&
5062                         (strcmp(tokens[2], "port") == 0) &&
5063                         (strcmp(tokens[3], "out") == 0) &&
5064                         (strcmp(tokens[4], "bsz") == 0)) {
5065                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
5066                         return;
5067                 }
5068
5069                 if ((n_tokens >= 4) &&
5070                         (strcmp(tokens[2], "table") == 0) &&
5071                         (strcmp(tokens[3], "match") == 0)) {
5072                         cmd_pipeline_table(tokens, n_tokens, out, out_size);
5073                         return;
5074                 }
5075
5076                 if ((n_tokens >= 6) &&
5077                         (strcmp(tokens[2], "port") == 0) &&
5078                         (strcmp(tokens[3], "in") == 0) &&
5079                         (strcmp(tokens[5], "table") == 0)) {
5080                         cmd_pipeline_port_in_table(tokens, n_tokens,
5081                                 out, out_size);
5082                         return;
5083                 }
5084
5085                 if ((n_tokens >= 6) &&
5086                         (strcmp(tokens[2], "port") == 0) &&
5087                         (strcmp(tokens[3], "in") == 0) &&
5088                         (strcmp(tokens[5], "stats") == 0)) {
5089                         cmd_pipeline_port_in_stats(tokens, n_tokens,
5090                                 out, out_size);
5091                         return;
5092                 }
5093
5094                 if ((n_tokens >= 6) &&
5095                         (strcmp(tokens[2], "port") == 0) &&
5096                         (strcmp(tokens[3], "in") == 0) &&
5097                         (strcmp(tokens[5], "enable") == 0)) {
5098                         cmd_pipeline_port_in_enable(tokens, n_tokens,
5099                                 out, out_size);
5100                         return;
5101                 }
5102
5103                 if ((n_tokens >= 6) &&
5104                         (strcmp(tokens[2], "port") == 0) &&
5105                         (strcmp(tokens[3], "in") == 0) &&
5106                         (strcmp(tokens[5], "disable") == 0)) {
5107                         cmd_pipeline_port_in_disable(tokens, n_tokens,
5108                                 out, out_size);
5109                         return;
5110                 }
5111
5112                 if ((n_tokens >= 6) &&
5113                         (strcmp(tokens[2], "port") == 0) &&
5114                         (strcmp(tokens[3], "out") == 0) &&
5115                         (strcmp(tokens[5], "stats") == 0)) {
5116                         cmd_pipeline_port_out_stats(tokens, n_tokens,
5117                                 out, out_size);
5118                         return;
5119                 }
5120
5121                 if ((n_tokens >= 5) &&
5122                         (strcmp(tokens[2], "table") == 0) &&
5123                         (strcmp(tokens[4], "stats") == 0)) {
5124                         cmd_pipeline_table_stats(tokens, n_tokens,
5125                                 out, out_size);
5126                         return;
5127                 }
5128
5129                 if ((n_tokens >= 7) &&
5130                         (strcmp(tokens[2], "table") == 0) &&
5131                         (strcmp(tokens[4], "rule") == 0) &&
5132                         (strcmp(tokens[5], "add") == 0) &&
5133                         (strcmp(tokens[6], "match") == 0)) {
5134                         if ((n_tokens >= 8) &&
5135                                 (strcmp(tokens[7], "default") == 0)) {
5136                                 cmd_pipeline_table_rule_add_default(tokens,
5137                                         n_tokens, out, out_size);
5138                                 return;
5139                         }
5140
5141                         cmd_pipeline_table_rule_add(tokens, n_tokens,
5142                                 out, out_size);
5143                         return;
5144                 }
5145
5146                 if ((n_tokens >= 7) &&
5147                         (strcmp(tokens[2], "table") == 0) &&
5148                         (strcmp(tokens[4], "rule") == 0) &&
5149                         (strcmp(tokens[5], "add") == 0) &&
5150                         (strcmp(tokens[6], "bulk") == 0)) {
5151                         cmd_pipeline_table_rule_add_bulk(tokens,
5152                                 n_tokens, out, out_size);
5153                         return;
5154                 }
5155
5156                 if ((n_tokens >= 7) &&
5157                         (strcmp(tokens[2], "table") == 0) &&
5158                         (strcmp(tokens[4], "rule") == 0) &&
5159                         (strcmp(tokens[5], "delete") == 0) &&
5160                         (strcmp(tokens[6], "match") == 0)) {
5161                         if ((n_tokens >= 8) &&
5162                                 (strcmp(tokens[7], "default") == 0)) {
5163                                 cmd_pipeline_table_rule_delete_default(tokens,
5164                                         n_tokens, out, out_size);
5165                                 return;
5166                                 }
5167
5168                         cmd_pipeline_table_rule_delete(tokens, n_tokens,
5169                                 out, out_size);
5170                         return;
5171                 }
5172
5173                 if ((n_tokens >= 7) &&
5174                         (strcmp(tokens[2], "table") == 0) &&
5175                         (strcmp(tokens[4], "rule") == 0) &&
5176                         (strcmp(tokens[5], "read") == 0) &&
5177                         (strcmp(tokens[6], "stats") == 0)) {
5178                         cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
5179                                 out, out_size);
5180                         return;
5181                 }
5182
5183                 if ((n_tokens >= 8) &&
5184                         (strcmp(tokens[2], "table") == 0) &&
5185                         (strcmp(tokens[4], "meter") == 0) &&
5186                         (strcmp(tokens[5], "profile") == 0) &&
5187                         (strcmp(tokens[7], "add") == 0)) {
5188                         cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
5189                                 out, out_size);
5190                         return;
5191                 }
5192
5193                 if ((n_tokens >= 8) &&
5194                         (strcmp(tokens[2], "table") == 0) &&
5195                         (strcmp(tokens[4], "meter") == 0) &&
5196                         (strcmp(tokens[5], "profile") == 0) &&
5197                         (strcmp(tokens[7], "delete") == 0)) {
5198                         cmd_pipeline_table_meter_profile_delete(tokens,
5199                                 n_tokens, out, out_size);
5200                         return;
5201                 }
5202
5203                 if ((n_tokens >= 7) &&
5204                         (strcmp(tokens[2], "table") == 0) &&
5205                         (strcmp(tokens[4], "rule") == 0) &&
5206                         (strcmp(tokens[5], "read") == 0) &&
5207                         (strcmp(tokens[6], "meter") == 0)) {
5208                         cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
5209                                 out, out_size);
5210                         return;
5211                 }
5212
5213                 if ((n_tokens >= 5) &&
5214                         (strcmp(tokens[2], "table") == 0) &&
5215                         (strcmp(tokens[4], "dscp") == 0)) {
5216                         cmd_pipeline_table_dscp(tokens, n_tokens,
5217                                 out, out_size);
5218                         return;
5219                 }
5220
5221                 if ((n_tokens >= 7) &&
5222                         (strcmp(tokens[2], "table") == 0) &&
5223                         (strcmp(tokens[4], "rule") == 0) &&
5224                         (strcmp(tokens[5], "read") == 0) &&
5225                         (strcmp(tokens[6], "ttl") == 0)) {
5226                         cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
5227                                 out, out_size);
5228                         return;
5229                 }
5230         }
5231
5232         if (strcmp(tokens[0], "thread") == 0) {
5233                 if ((n_tokens >= 5) &&
5234                         (strcmp(tokens[4], "enable") == 0)) {
5235                         cmd_thread_pipeline_enable(tokens, n_tokens,
5236                                 out, out_size);
5237                         return;
5238                 }
5239
5240                 if ((n_tokens >= 5) &&
5241                         (strcmp(tokens[4], "disable") == 0)) {
5242                         cmd_thread_pipeline_disable(tokens, n_tokens,
5243                                 out, out_size);
5244                         return;
5245                 }
5246         }
5247
5248         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
5249 }
5250
5251 int
5252 cli_script_process(const char *file_name,
5253         size_t msg_in_len_max,
5254         size_t msg_out_len_max)
5255 {
5256         char *msg_in = NULL, *msg_out = NULL;
5257         FILE *f = NULL;
5258
5259         /* Check input arguments */
5260         if ((file_name == NULL) ||
5261                 (strlen(file_name) == 0) ||
5262                 (msg_in_len_max == 0) ||
5263                 (msg_out_len_max == 0))
5264                 return -EINVAL;
5265
5266         msg_in = malloc(msg_in_len_max + 1);
5267         msg_out = malloc(msg_out_len_max + 1);
5268         if ((msg_in == NULL) ||
5269                 (msg_out == NULL)) {
5270                 free(msg_out);
5271                 free(msg_in);
5272                 return -ENOMEM;
5273         }
5274
5275         /* Open input file */
5276         f = fopen(file_name, "r");
5277         if (f == NULL) {
5278                 free(msg_out);
5279                 free(msg_in);
5280                 return -EIO;
5281         }
5282
5283         /* Read file */
5284         for ( ; ; ) {
5285                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
5286                         break;
5287
5288                 printf("%s", msg_in);
5289                 msg_out[0] = 0;
5290
5291                 cli_process(msg_in,
5292                         msg_out,
5293                         msg_out_len_max);
5294
5295                 if (strlen(msg_out))
5296                         printf("%s", msg_out);
5297         }
5298
5299         /* Close file */
5300         fclose(f);
5301         free(msg_out);
5302         free(msg_in);
5303         return 0;
5304 }
5305
5306 static int
5307 cli_rule_file_process(const char *file_name,
5308         size_t line_len_max,
5309         struct table_rule_match *m,
5310         struct table_rule_action *a,
5311         uint32_t *n_rules,
5312         uint32_t *line_number,
5313         char *out,
5314         size_t out_size)
5315 {
5316         FILE *f = NULL;
5317         char *line = NULL;
5318         uint32_t rule_id, line_id;
5319         int status = 0;
5320
5321         /* Check input arguments */
5322         if ((file_name == NULL) ||
5323                 (strlen(file_name) == 0) ||
5324                 (line_len_max == 0)) {
5325                 *line_number = 0;
5326                 return -EINVAL;
5327         }
5328
5329         /* Memory allocation */
5330         line = malloc(line_len_max + 1);
5331         if (line == NULL) {
5332                 *line_number = 0;
5333                 return -ENOMEM;
5334         }
5335
5336         /* Open file */
5337         f = fopen(file_name, "r");
5338         if (f == NULL) {
5339                 *line_number = 0;
5340                 free(line);
5341                 return -EIO;
5342         }
5343
5344         /* Read file */
5345         for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
5346                 char *tokens[CMD_MAX_TOKENS];
5347                 uint32_t n_tokens, n_tokens_parsed, t0;
5348
5349                 /* Read next line from file. */
5350                 if (fgets(line, line_len_max + 1, f) == NULL)
5351                         break;
5352
5353                 /* Comment. */
5354                 if (is_comment(line))
5355                         continue;
5356
5357                 /* Parse line. */
5358                 n_tokens = RTE_DIM(tokens);
5359                 status = parse_tokenize_string(line, tokens, &n_tokens);
5360                 if (status) {
5361                         status = -EINVAL;
5362                         break;
5363                 }
5364
5365                 /* Empty line. */
5366                 if (n_tokens == 0)
5367                         continue;
5368                 t0 = 0;
5369
5370                 /* Rule match. */
5371                 n_tokens_parsed = parse_match(tokens + t0,
5372                         n_tokens - t0,
5373                         out,
5374                         out_size,
5375                         &m[rule_id]);
5376                 if (n_tokens_parsed == 0) {
5377                         status = -EINVAL;
5378                         break;
5379                 }
5380                 t0 += n_tokens_parsed;
5381
5382                 /* Rule action. */
5383                 n_tokens_parsed = parse_table_action(tokens + t0,
5384                         n_tokens - t0,
5385                         out,
5386                         out_size,
5387                         &a[rule_id]);
5388                 if (n_tokens_parsed == 0) {
5389                         status = -EINVAL;
5390                         break;
5391                 }
5392                 t0 += n_tokens_parsed;
5393
5394                 /* Line completed. */
5395                 if (t0 < n_tokens) {
5396                         status = -EINVAL;
5397                         break;
5398                 }
5399
5400                 /* Increment rule count */
5401                 rule_id++;
5402         }
5403
5404         /* Close file */
5405         fclose(f);
5406
5407         /* Memory free */
5408         free(line);
5409
5410         *n_rules = rule_id;
5411         *line_number = line_id;
5412         return status;
5413 }