examples/ip_pipeline: add table entry stats command
[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
13 #include "cli.h"
14 #include "kni.h"
15 #include "link.h"
16 #include "mempool.h"
17 #include "parser.h"
18 #include "pipeline.h"
19 #include "swq.h"
20 #include "tap.h"
21 #include "thread.h"
22 #include "tmgr.h"
23
24 #ifndef CMD_MAX_TOKENS
25 #define CMD_MAX_TOKENS     256
26 #endif
27
28 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
29 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
30 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
31 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
32 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
33 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
34 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
35 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
36 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
37 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
38 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
39
40 static int
41 is_comment(char *in)
42 {
43         if ((strlen(in) && index("!#%;", in[0])) ||
44                 (strncmp(in, "//", 2) == 0) ||
45                 (strncmp(in, "--", 2) == 0))
46                 return 1;
47
48         return 0;
49 }
50
51 /**
52  * mempool <mempool_name>
53  *  buffer <buffer_size>
54  *  pool <pool_size>
55  *  cache <cache_size>
56  *  cpu <cpu_id>
57  */
58 static void
59 cmd_mempool(char **tokens,
60         uint32_t n_tokens,
61         char *out,
62         size_t out_size)
63 {
64         struct mempool_params p;
65         char *name;
66         struct mempool *mempool;
67
68         if (n_tokens != 10) {
69                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
70                 return;
71         }
72
73         name = tokens[1];
74
75         if (strcmp(tokens[2], "buffer") != 0) {
76                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
77                 return;
78         }
79
80         if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
81                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
82                 return;
83         }
84
85         if (strcmp(tokens[4], "pool") != 0) {
86                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
87                 return;
88         }
89
90         if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
91                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
92                 return;
93         }
94
95         if (strcmp(tokens[6], "cache") != 0) {
96                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
97                 return;
98         }
99
100         if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
101                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
102                 return;
103         }
104
105         if (strcmp(tokens[8], "cpu") != 0) {
106                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
107                 return;
108         }
109
110         if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
111                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
112                 return;
113         }
114
115         mempool = mempool_create(name, &p);
116         if (mempool == NULL) {
117                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
118                 return;
119         }
120 }
121
122 /**
123  * link <link_name>
124  *  dev <device_name> | port <port_id>
125  *  rxq <n_queues> <queue_size> <mempool_name>
126  *  txq <n_queues> <queue_size>
127  *  promiscuous on | off
128  *  [rss <qid_0> ... <qid_n>]
129  */
130 static void
131 cmd_link(char **tokens,
132         uint32_t n_tokens,
133         char *out,
134         size_t out_size)
135 {
136         struct link_params p;
137         struct link_params_rss rss;
138         struct link *link;
139         char *name;
140
141         if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
142                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
143                 return;
144         }
145         name = tokens[1];
146
147         if (strcmp(tokens[2], "dev") == 0)
148                 p.dev_name = tokens[3];
149         else if (strcmp(tokens[2], "port") == 0) {
150                 p.dev_name = NULL;
151
152                 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
153                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
154                         return;
155                 }
156         } else {
157                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
158                 return;
159         }
160
161         if (strcmp(tokens[4], "rxq") != 0) {
162                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
163                 return;
164         }
165
166         if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
167                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
168                 return;
169         }
170         if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
171                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
172                 return;
173         }
174
175         p.rx.mempool_name = tokens[7];
176
177         if (strcmp(tokens[8], "txq") != 0) {
178                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
179                 return;
180         }
181
182         if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
183                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
184                 return;
185         }
186
187         if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
188                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
189                 return;
190         }
191
192         if (strcmp(tokens[11], "promiscuous") != 0) {
193                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
194                 return;
195         }
196
197         if (strcmp(tokens[12], "on") == 0)
198                 p.promiscuous = 1;
199         else if (strcmp(tokens[12], "off") == 0)
200                 p.promiscuous = 0;
201         else {
202                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
203                 return;
204         }
205
206         /* RSS */
207         p.rx.rss = NULL;
208         if (n_tokens > 13) {
209                 uint32_t queue_id, i;
210
211                 if (strcmp(tokens[13], "rss") != 0) {
212                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
213                         return;
214                 }
215
216                 p.rx.rss = &rss;
217
218                 rss.n_queues = 0;
219                 for (i = 14; i < n_tokens; i++) {
220                         if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
221                                 snprintf(out, out_size, MSG_ARG_INVALID,
222                                         "queue_id");
223                                 return;
224                         }
225
226                         rss.queue_id[rss.n_queues] = queue_id;
227                         rss.n_queues++;
228                 }
229         }
230
231         link = link_create(name, &p);
232         if (link == NULL) {
233                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
234                 return;
235         }
236 }
237
238 /**
239  * swq <swq_name>
240  *  size <size>
241  *  cpu <cpu_id>
242  */
243 static void
244 cmd_swq(char **tokens,
245         uint32_t n_tokens,
246         char *out,
247         size_t out_size)
248 {
249         struct swq_params p;
250         char *name;
251         struct swq *swq;
252
253         if (n_tokens != 6) {
254                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
255                 return;
256         }
257
258         name = tokens[1];
259
260         if (strcmp(tokens[2], "size") != 0) {
261                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
262                 return;
263         }
264
265         if (parser_read_uint32(&p.size, tokens[3]) != 0) {
266                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
267                 return;
268         }
269
270         if (strcmp(tokens[4], "cpu") != 0) {
271                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
272                 return;
273         }
274
275         if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
276                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
277                 return;
278         }
279
280         swq = swq_create(name, &p);
281         if (swq == NULL) {
282                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
283                 return;
284         }
285 }
286
287 /**
288  * tmgr subport profile
289  *  <tb_rate> <tb_size>
290  *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
291  *  <tc_period>
292  */
293 static void
294 cmd_tmgr_subport_profile(char **tokens,
295         uint32_t n_tokens,
296         char *out,
297         size_t out_size)
298 {
299         struct rte_sched_subport_params p;
300         int status, i;
301
302         if (n_tokens != 10) {
303                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
304                 return;
305         }
306
307         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
308                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
309                 return;
310         }
311
312         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
313                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
314                 return;
315         }
316
317         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
318                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
319                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
320                         return;
321                 }
322
323         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
324                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
325                 return;
326         }
327
328         status = tmgr_subport_profile_add(&p);
329         if (status != 0) {
330                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
331                 return;
332         }
333 }
334
335 /**
336  * tmgr pipe profile
337  *  <tb_rate> <tb_size>
338  *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
339  *  <tc_period>
340  *  <tc_ov_weight>
341  *  <wrr_weight0..15>
342  */
343 static void
344 cmd_tmgr_pipe_profile(char **tokens,
345         uint32_t n_tokens,
346         char *out,
347         size_t out_size)
348 {
349         struct rte_sched_pipe_params p;
350         int status, i;
351
352         if (n_tokens != 27) {
353                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
354                 return;
355         }
356
357         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
358                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
359                 return;
360         }
361
362         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
363                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
364                 return;
365         }
366
367         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
368                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
369                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
370                         return;
371                 }
372
373         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
374                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
375                 return;
376         }
377
378 #ifdef RTE_SCHED_SUBPORT_TC_OV
379         if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) {
380                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
381                 return;
382         }
383 #endif
384
385         for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
386                 if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
387                         snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
388                         return;
389                 }
390
391         status = tmgr_pipe_profile_add(&p);
392         if (status != 0) {
393                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
394                 return;
395         }
396 }
397
398 /**
399  * tmgr <tmgr_name>
400  *  rate <rate>
401  *  spp <n_subports_per_port>
402  *  pps <n_pipes_per_subport>
403  *  qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>
404  *  fo <frame_overhead>
405  *  mtu <mtu>
406  *  cpu <cpu_id>
407  */
408 static void
409 cmd_tmgr(char **tokens,
410         uint32_t n_tokens,
411         char *out,
412         size_t out_size)
413 {
414         struct tmgr_port_params p;
415         char *name;
416         struct tmgr_port *tmgr_port;
417         int i;
418
419         if (n_tokens != 19) {
420                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
421                 return;
422         }
423
424         name = tokens[1];
425
426         if (strcmp(tokens[2], "rate") != 0) {
427                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
428                 return;
429         }
430
431         if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
432                 snprintf(out, out_size, MSG_ARG_INVALID, "rate");
433                 return;
434         }
435
436         if (strcmp(tokens[4], "spp") != 0) {
437                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
438                 return;
439         }
440
441         if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
442                 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
443                 return;
444         }
445
446         if (strcmp(tokens[6], "pps") != 0) {
447                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
448                 return;
449         }
450
451         if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
452                 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
453                 return;
454         }
455
456         if (strcmp(tokens[8], "qsize") != 0) {
457                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
458                 return;
459         }
460
461         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
462                 if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
463                         snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
464                         return;
465                 }
466
467         if (strcmp(tokens[13], "fo") != 0) {
468                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
469                 return;
470         }
471
472         if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
473                 snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
474                 return;
475         }
476
477         if (strcmp(tokens[15], "mtu") != 0) {
478                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
479                 return;
480         }
481
482         if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
483                 snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
484                 return;
485         }
486
487         if (strcmp(tokens[17], "cpu") != 0) {
488                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
489                 return;
490         }
491
492         if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
493                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
494                 return;
495         }
496
497         tmgr_port = tmgr_port_create(name, &p);
498         if (tmgr_port == NULL) {
499                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
500                 return;
501         }
502 }
503
504 /**
505  * tmgr <tmgr_name> subport <subport_id>
506  *  profile <subport_profile_id>
507  */
508 static void
509 cmd_tmgr_subport(char **tokens,
510         uint32_t n_tokens,
511         char *out,
512         size_t out_size)
513 {
514         uint32_t subport_id, subport_profile_id;
515         int status;
516         char *name;
517
518         if (n_tokens != 6) {
519                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
520                 return;
521         }
522
523         name = tokens[1];
524
525         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
526                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
527                 return;
528         }
529
530         if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
531                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
532                 return;
533         }
534
535         status = tmgr_subport_config(name, subport_id, subport_profile_id);
536         if (status) {
537                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
538                 return;
539         }
540 }
541
542 /**
543  * tmgr <tmgr_name> subport <subport_id> pipe
544  *  from <pipe_id_first> to <pipe_id_last>
545  *  profile <pipe_profile_id>
546  */
547 static void
548 cmd_tmgr_subport_pipe(char **tokens,
549         uint32_t n_tokens,
550         char *out,
551         size_t out_size)
552 {
553         uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
554         int status;
555         char *name;
556
557         if (n_tokens != 11) {
558                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
559                 return;
560         }
561
562         name = tokens[1];
563
564         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
565                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
566                 return;
567         }
568
569         if (strcmp(tokens[4], "pipe") != 0) {
570                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
571                 return;
572         }
573
574         if (strcmp(tokens[5], "from") != 0) {
575                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
576                 return;
577         }
578
579         if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
580                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
581                 return;
582         }
583
584         if (strcmp(tokens[7], "to") != 0) {
585                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
586                 return;
587         }
588
589         if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
590                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
591                 return;
592         }
593
594         if (strcmp(tokens[9], "profile") != 0) {
595                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
596                 return;
597         }
598
599         if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
600                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
601                 return;
602         }
603
604         status = tmgr_pipe_config(name, subport_id, pipe_id_first,
605                         pipe_id_last, pipe_profile_id);
606         if (status) {
607                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
608                 return;
609         }
610 }
611
612 /**
613  * tap <tap_name>
614  */
615 static void
616 cmd_tap(char **tokens,
617         uint32_t n_tokens,
618         char *out,
619         size_t out_size)
620 {
621         char *name;
622         struct tap *tap;
623
624         if (n_tokens != 2) {
625                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
626                 return;
627         }
628
629         name = tokens[1];
630
631         tap = tap_create(name);
632         if (tap == NULL) {
633                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
634                 return;
635         }
636 }
637
638 /**
639  * kni <kni_name>
640  *  link <link_name>
641  *  mempool <mempool_name>
642  *  [thread <thread_id>]
643  */
644 static void
645 cmd_kni(char **tokens,
646         uint32_t n_tokens,
647         char *out,
648         size_t out_size)
649 {
650         struct kni_params p;
651         char *name;
652         struct kni *kni;
653
654         if ((n_tokens != 6) && (n_tokens != 8)) {
655                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
656                 return;
657         }
658
659         name = tokens[1];
660
661         if (strcmp(tokens[2], "link") != 0) {
662                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
663                 return;
664         }
665
666         p.link_name = tokens[3];
667
668         if (strcmp(tokens[4], "mempool") != 0) {
669                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
670                 return;
671         }
672
673         p.mempool_name = tokens[5];
674
675         if (n_tokens == 8) {
676                 if (strcmp(tokens[6], "thread") != 0) {
677                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
678                         return;
679                 }
680
681                 if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
682                         snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
683                         return;
684                 }
685
686                 p.force_bind = 1;
687         } else
688                 p.force_bind = 0;
689
690         kni = kni_create(name, &p);
691         if (kni == NULL) {
692                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
693                 return;
694         }
695 }
696
697 /**
698  * port in action profile <profile_name>
699  *  [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]
700  *  [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]
701  */
702 static void
703 cmd_port_in_action_profile(char **tokens,
704         uint32_t n_tokens,
705         char *out,
706         size_t out_size)
707 {
708         struct port_in_action_profile_params p;
709         struct port_in_action_profile *ap;
710         char *name;
711         uint32_t t0;
712
713         memset(&p, 0, sizeof(p));
714
715         if (n_tokens < 5) {
716                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
717                 return;
718         }
719
720         if (strcmp(tokens[1], "in") != 0) {
721                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
722                 return;
723         }
724
725         if (strcmp(tokens[2], "action") != 0) {
726                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
727                 return;
728         }
729
730         if (strcmp(tokens[3], "profile") != 0) {
731                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
732                 return;
733         }
734
735         name = tokens[4];
736
737         t0 = 5;
738
739         if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) {
740                 uint32_t size;
741
742                 if (n_tokens < t0 + 10) {
743                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
744                         return;
745                 }
746
747                 if (strcmp(tokens[t0 + 1], "match") == 0)
748                         p.fltr.filter_on_match = 1;
749                 else if (strcmp(tokens[t0 + 1], "mismatch") == 0)
750                         p.fltr.filter_on_match = 0;
751                 else {
752                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
753                         return;
754                 }
755
756                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
757                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
758                         return;
759                 }
760
761                 if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) {
762                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
763                         return;
764                 }
765
766                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
767                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
768                         return;
769                 }
770
771                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
772                 if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) ||
773                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
774                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
775                         return;
776                 }
777
778                 if (strcmp(tokens[t0 + 6], "key") != 0) {
779                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
780                         return;
781                 }
782
783                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
784                 if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) ||
785                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
786                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
787                         return;
788                 }
789
790                 if (strcmp(tokens[t0 + 8], "port") != 0) {
791                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
792                         return;
793                 }
794
795                 if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) {
796                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
797                         return;
798                 }
799
800                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
801                 t0 += 10;
802         } /* filter */
803
804         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
805                 uint32_t i;
806
807                 if (n_tokens < t0 + 22) {
808                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile balance");
809                         return;
810                 }
811
812                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
813                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
814                         return;
815                 }
816
817                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
818                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
819                         return;
820                 }
821
822                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
823                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
824                         return;
825                 }
826
827                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
828                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
829                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
830                         return;
831                 }
832
833                 if (strcmp(tokens[t0 + 5], "port") != 0) {
834                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
835                         return;
836                 }
837
838                 for (i = 0; i < 16; i++)
839                         if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) {
840                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
841                                 return;
842                         }
843
844                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
845                 t0 += 22;
846         } /* balance */
847
848         if (t0 < n_tokens) {
849                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
850                 return;
851         }
852
853         ap = port_in_action_profile_create(name, &p);
854         if (ap == NULL) {
855                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
856                 return;
857         }
858 }
859
860 /**
861  * table action profile <profile_name>
862  *  ipv4 | ipv6
863  *  offset <ip_offset>
864  *  fwd
865  *  [meter srtcm | trtcm
866  *      tc <n_tc>
867  *      stats none | pkts | bytes | both]
868  *  [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
869  *  [encap ether | vlan | qinq | mpls | pppoe]
870  *  [nat src | dst
871  *      proto udp | tcp]
872  *  [ttl drop | fwd
873  *      stats none | pkts]
874  *  [stats pkts | bytes | both]
875  *  [time]
876  */
877 static void
878 cmd_table_action_profile(char **tokens,
879         uint32_t n_tokens,
880         char *out,
881         size_t out_size)
882 {
883         struct table_action_profile_params p;
884         struct table_action_profile *ap;
885         char *name;
886         uint32_t t0;
887
888         memset(&p, 0, sizeof(p));
889
890         if (n_tokens < 8) {
891                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
892                 return;
893         }
894
895         if (strcmp(tokens[1], "action") != 0) {
896                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
897                 return;
898         }
899
900         if (strcmp(tokens[2], "profile") != 0) {
901                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
902                 return;
903         }
904
905         name = tokens[3];
906
907         if (strcmp(tokens[4], "ipv4") == 0)
908                 p.common.ip_version = 1;
909         else if (strcmp(tokens[4], "ipv6") == 0)
910                 p.common.ip_version = 0;
911         else {
912                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
913                 return;
914         }
915
916         if (strcmp(tokens[5], "offset") != 0) {
917                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
918                 return;
919         }
920
921         if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
922                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
923                 return;
924         }
925
926         if (strcmp(tokens[7], "fwd") != 0) {
927                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
928                 return;
929         }
930
931         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
932
933         t0 = 8;
934         if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
935                 if (n_tokens < t0 + 6) {
936                         snprintf(out, out_size, MSG_ARG_MISMATCH,
937                                 "table action profile meter");
938                         return;
939                 }
940
941                 if (strcmp(tokens[t0 + 1], "srtcm") == 0)
942                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
943                 else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
944                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
945                 else {
946                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
947                                 "srtcm or trtcm");
948                         return;
949                 }
950
951                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
952                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
953                         return;
954                 }
955
956                 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
957                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
958                         return;
959                 }
960
961                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
962                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
963                         return;
964                 }
965
966                 if (strcmp(tokens[t0 + 5], "none") == 0) {
967                         p.mtr.n_packets_enabled = 0;
968                         p.mtr.n_bytes_enabled = 0;
969                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
970                         p.mtr.n_packets_enabled = 1;
971                         p.mtr.n_bytes_enabled = 0;
972                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
973                         p.mtr.n_packets_enabled = 0;
974                         p.mtr.n_bytes_enabled = 1;
975                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
976                         p.mtr.n_packets_enabled = 1;
977                         p.mtr.n_bytes_enabled = 1;
978                 } else {
979                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
980                                 "none or pkts or bytes or both");
981                         return;
982                 }
983
984                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
985                 t0 += 6;
986         } /* meter */
987
988         if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
989                 if (n_tokens < t0 + 5) {
990                         snprintf(out, out_size, MSG_ARG_MISMATCH,
991                                 "table action profile tm");
992                         return;
993                 }
994
995                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
996                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
997                         return;
998                 }
999
1000                 if (parser_read_uint32(&p.tm.n_subports_per_port,
1001                         tokens[t0 + 2]) != 0) {
1002                         snprintf(out, out_size, MSG_ARG_INVALID,
1003                                 "n_subports_per_port");
1004                         return;
1005                 }
1006
1007                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
1008                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1009                         return;
1010                 }
1011
1012                 if (parser_read_uint32(&p.tm.n_pipes_per_subport,
1013                         tokens[t0 + 4]) != 0) {
1014                         snprintf(out, out_size, MSG_ARG_INVALID,
1015                                 "n_pipes_per_subport");
1016                         return;
1017                 }
1018
1019                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1020                 t0 += 5;
1021         } /* tm */
1022
1023         if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
1024                 if (n_tokens < t0 + 2) {
1025                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1026                                 "action profile encap");
1027                         return;
1028                 }
1029
1030                 if (strcmp(tokens[t0 + 1], "ether") == 0)
1031                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1032                 else if (strcmp(tokens[t0 + 1], "vlan") == 0)
1033                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1034                 else if (strcmp(tokens[t0 + 1], "qinq") == 0)
1035                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1036                 else if (strcmp(tokens[t0 + 1], "mpls") == 0)
1037                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1038                 else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
1039                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1040                 else {
1041                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1042                         return;
1043                 }
1044
1045                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1046                 t0 += 2;
1047         } /* encap */
1048
1049         if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
1050                 if (n_tokens < t0 + 4) {
1051                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1052                                 "table action profile nat");
1053                         return;
1054                 }
1055
1056                 if (strcmp(tokens[t0 + 1], "src") == 0)
1057                         p.nat.source_nat = 1;
1058                 else if (strcmp(tokens[t0 + 1], "dst") == 0)
1059                         p.nat.source_nat = 0;
1060                 else {
1061                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1062                                 "src or dst");
1063                         return;
1064                 }
1065
1066                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
1067                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1068                         return;
1069                 }
1070
1071                 if (strcmp(tokens[t0 + 3], "tcp") == 0)
1072                         p.nat.proto = 0x06;
1073                 else if (strcmp(tokens[t0 + 3], "udp") == 0)
1074                         p.nat.proto = 0x11;
1075                 else {
1076                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1077                                 "tcp or udp");
1078                         return;
1079                 }
1080
1081                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1082                 t0 += 4;
1083         } /* nat */
1084
1085         if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
1086                 if (n_tokens < t0 + 4) {
1087                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1088                                 "table action profile ttl");
1089                         return;
1090                 }
1091
1092                 if (strcmp(tokens[t0 + 1], "drop") == 0)
1093                         p.ttl.drop = 1;
1094                 else if (strcmp(tokens[t0 + 1], "fwd") == 0)
1095                         p.ttl.drop = 0;
1096                 else {
1097                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1098                                 "drop or fwd");
1099                         return;
1100                 }
1101
1102                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
1103                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1104                         return;
1105                 }
1106
1107                 if (strcmp(tokens[t0 + 3], "none") == 0)
1108                         p.ttl.n_packets_enabled = 0;
1109                 else if (strcmp(tokens[t0 + 3], "pkts") == 0)
1110                         p.ttl.n_packets_enabled = 1;
1111                 else {
1112                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1113                                 "none or pkts");
1114                         return;
1115                 }
1116
1117                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1118                 t0 += 4;
1119         } /* ttl */
1120
1121         if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
1122                 if (n_tokens < t0 + 2) {
1123                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1124                                 "table action profile stats");
1125                         return;
1126                 }
1127
1128                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1129                         p.stats.n_packets_enabled = 1;
1130                         p.stats.n_bytes_enabled = 0;
1131                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1132                         p.stats.n_packets_enabled = 0;
1133                         p.stats.n_bytes_enabled = 1;
1134                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
1135                         p.stats.n_packets_enabled = 1;
1136                         p.stats.n_bytes_enabled = 1;
1137                 } else {
1138                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1139                                 "pkts or bytes or both");
1140                         return;
1141                 }
1142
1143                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1144                 t0 += 2;
1145         } /* stats */
1146
1147         if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
1148                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1149                 t0 += 1;
1150         } /* time */
1151
1152         if (t0 < n_tokens) {
1153                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1154                 return;
1155         }
1156
1157         ap = table_action_profile_create(name, &p);
1158         if (ap == NULL) {
1159                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1160                 return;
1161         }
1162 }
1163
1164 /**
1165  * pipeline <pipeline_name>
1166  *  period <timer_period_ms>
1167  *  offset_port_id <offset_port_id>
1168  *  cpu <cpu_id>
1169  */
1170 static void
1171 cmd_pipeline(char **tokens,
1172         uint32_t n_tokens,
1173         char *out,
1174         size_t out_size)
1175 {
1176         struct pipeline_params p;
1177         char *name;
1178         struct pipeline *pipeline;
1179
1180         if (n_tokens != 8) {
1181                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1182                 return;
1183         }
1184
1185         name = tokens[1];
1186
1187         if (strcmp(tokens[2], "period") != 0) {
1188                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
1189                 return;
1190         }
1191
1192         if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
1193                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
1194                 return;
1195         }
1196
1197         if (strcmp(tokens[4], "offset_port_id") != 0) {
1198                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
1199                 return;
1200         }
1201
1202         if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
1203                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
1204                 return;
1205         }
1206
1207         if (strcmp(tokens[6], "cpu") != 0) {
1208                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
1209                 return;
1210         }
1211
1212         if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
1213                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
1214                 return;
1215         }
1216
1217         pipeline = pipeline_create(name, &p);
1218         if (pipeline == NULL) {
1219                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1220                 return;
1221         }
1222 }
1223
1224 /**
1225  * pipeline <pipeline_name> port in
1226  *  bsz <burst_size>
1227  *  link <link_name> rxq <queue_id>
1228  *  | swq <swq_name>
1229  *  | tmgr <tmgr_name>
1230  *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
1231  *  | kni <kni_name>
1232  *  | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>
1233  *  [action <port_in_action_profile_name>]
1234  *  [disabled]
1235  */
1236 static void
1237 cmd_pipeline_port_in(char **tokens,
1238         uint32_t n_tokens,
1239         char *out,
1240         size_t out_size)
1241 {
1242         struct port_in_params p;
1243         char *pipeline_name;
1244         uint32_t t0;
1245         int enabled, status;
1246
1247         if (n_tokens < 7) {
1248                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1249                 return;
1250         }
1251
1252         pipeline_name = tokens[1];
1253
1254         if (strcmp(tokens[2], "port") != 0) {
1255                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1256                 return;
1257         }
1258
1259         if (strcmp(tokens[3], "in") != 0) {
1260                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1261                 return;
1262         }
1263
1264         if (strcmp(tokens[4], "bsz") != 0) {
1265                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1266                 return;
1267         }
1268
1269         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1270                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1271                 return;
1272         }
1273
1274         t0 = 6;
1275
1276         if (strcmp(tokens[t0], "link") == 0) {
1277                 if (n_tokens < t0 + 4) {
1278                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1279                                 "pipeline port in link");
1280                         return;
1281                 }
1282
1283                 p.type = PORT_IN_RXQ;
1284
1285                 p.dev_name = tokens[t0 + 1];
1286
1287                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
1288                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
1289                         return;
1290                 }
1291
1292                 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1293                         snprintf(out, out_size, MSG_ARG_INVALID,
1294                                 "queue_id");
1295                         return;
1296                 }
1297                 t0 += 4;
1298         } else if (strcmp(tokens[t0], "swq") == 0) {
1299                 if (n_tokens < t0 + 2) {
1300                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1301                                 "pipeline port in swq");
1302                         return;
1303                 }
1304
1305                 p.type = PORT_IN_SWQ;
1306
1307                 p.dev_name = tokens[t0 + 1];
1308
1309                 t0 += 2;
1310         } else if (strcmp(tokens[t0], "tmgr") == 0) {
1311                 if (n_tokens < t0 + 2) {
1312                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1313                                 "pipeline port in tmgr");
1314                         return;
1315                 }
1316
1317                 p.type = PORT_IN_TMGR;
1318
1319                 p.dev_name = tokens[t0 + 1];
1320
1321                 t0 += 2;
1322         } else if (strcmp(tokens[t0], "tap") == 0) {
1323                 if (n_tokens < t0 + 6) {
1324                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1325                                 "pipeline port in tap");
1326                         return;
1327                 }
1328
1329                 p.type = PORT_IN_TAP;
1330
1331                 p.dev_name = tokens[t0 + 1];
1332
1333                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
1334                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1335                                 "mempool");
1336                         return;
1337                 }
1338
1339                 p.tap.mempool_name = tokens[t0 + 3];
1340
1341                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
1342                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1343                                 "mtu");
1344                         return;
1345                 }
1346
1347                 if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
1348                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
1349                         return;
1350                 }
1351
1352                 t0 += 6;
1353         } else if (strcmp(tokens[t0], "kni") == 0) {
1354                 if (n_tokens < t0 + 2) {
1355                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1356                                 "pipeline port in kni");
1357                         return;
1358                 }
1359
1360                 p.type = PORT_IN_KNI;
1361
1362                 p.dev_name = tokens[t0 + 1];
1363
1364                 t0 += 2;
1365         } else if (strcmp(tokens[t0], "source") == 0) {
1366                 if (n_tokens < t0 + 6) {
1367                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1368                                 "pipeline port in source");
1369                         return;
1370                 }
1371
1372                 p.type = PORT_IN_SOURCE;
1373
1374                 p.dev_name = NULL;
1375
1376                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
1377                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1378                                 "mempool");
1379                         return;
1380                 }
1381
1382                 p.source.mempool_name = tokens[t0 + 2];
1383
1384                 if (strcmp(tokens[t0 + 3], "file") != 0) {
1385                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1386                                 "file");
1387                         return;
1388                 }
1389
1390                 p.source.file_name = tokens[t0 + 4];
1391
1392                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
1393                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1394                                 "bpp");
1395                         return;
1396                 }
1397
1398                 if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) {
1399                         snprintf(out, out_size, MSG_ARG_INVALID,
1400                                 "n_bytes_per_pkt");
1401                         return;
1402                 }
1403
1404                 t0 += 7;
1405         } else {
1406                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1407                 return;
1408         }
1409
1410         p.action_profile_name = NULL;
1411         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1412                 if (n_tokens < t0 + 2) {
1413                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1414                         return;
1415                 }
1416
1417                 p.action_profile_name = tokens[t0 + 1];
1418
1419                 t0 += 2;
1420         }
1421
1422         enabled = 1;
1423         if ((n_tokens > t0) &&
1424                 (strcmp(tokens[t0], "disabled") == 0)) {
1425                 enabled = 0;
1426
1427                 t0 += 1;
1428         }
1429
1430         if (n_tokens != t0) {
1431                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1432                 return;
1433         }
1434
1435         status = pipeline_port_in_create(pipeline_name,
1436                 &p, enabled);
1437         if (status) {
1438                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1439                 return;
1440         }
1441 }
1442
1443 /**
1444  * pipeline <pipeline_name> port out
1445  *  bsz <burst_size>
1446  *  link <link_name> txq <txq_id>
1447  *  | swq <swq_name>
1448  *  | tmgr <tmgr_name>
1449  *  | tap <tap_name>
1450  *  | kni <kni_name>
1451  *  | sink [file <file_name> pkts <max_n_pkts>]
1452  */
1453 static void
1454 cmd_pipeline_port_out(char **tokens,
1455         uint32_t n_tokens,
1456         char *out,
1457         size_t out_size)
1458 {
1459         struct port_out_params p;
1460         char *pipeline_name;
1461         int status;
1462
1463         memset(&p, 0, sizeof(p));
1464
1465         if (n_tokens < 7) {
1466                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1467                 return;
1468         }
1469
1470         pipeline_name = tokens[1];
1471
1472         if (strcmp(tokens[2], "port") != 0) {
1473                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1474                 return;
1475         }
1476
1477         if (strcmp(tokens[3], "out") != 0) {
1478                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1479                 return;
1480         }
1481
1482         if (strcmp(tokens[4], "bsz") != 0) {
1483                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1484                 return;
1485         }
1486
1487         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1488                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1489                 return;
1490         }
1491
1492         if (strcmp(tokens[6], "link") == 0) {
1493                 if (n_tokens != 10) {
1494                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1495                                 "pipeline port out link");
1496                         return;
1497                 }
1498
1499                 p.type = PORT_OUT_TXQ;
1500
1501                 p.dev_name = tokens[7];
1502
1503                 if (strcmp(tokens[8], "txq") != 0) {
1504                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1505                         return;
1506                 }
1507
1508                 if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
1509                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1510                         return;
1511                 }
1512         } else if (strcmp(tokens[6], "swq") == 0) {
1513                 if (n_tokens != 8) {
1514                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1515                                 "pipeline port out swq");
1516                         return;
1517                 }
1518
1519                 p.type = PORT_OUT_SWQ;
1520
1521                 p.dev_name = tokens[7];
1522         } else if (strcmp(tokens[6], "tmgr") == 0) {
1523                 if (n_tokens != 8) {
1524                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1525                                 "pipeline port out tmgr");
1526                         return;
1527                 }
1528
1529                 p.type = PORT_OUT_TMGR;
1530
1531                 p.dev_name = tokens[7];
1532         } else if (strcmp(tokens[6], "tap") == 0) {
1533                 if (n_tokens != 8) {
1534                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1535                                 "pipeline port out tap");
1536                         return;
1537                 }
1538
1539                 p.type = PORT_OUT_TAP;
1540
1541                 p.dev_name = tokens[7];
1542         } else if (strcmp(tokens[6], "kni") == 0) {
1543                 if (n_tokens != 8) {
1544                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1545                                 "pipeline port out kni");
1546                         return;
1547                 }
1548
1549                 p.type = PORT_OUT_KNI;
1550
1551                 p.dev_name = tokens[7];
1552         } else if (strcmp(tokens[6], "sink") == 0) {
1553                 if ((n_tokens != 7) && (n_tokens != 11)) {
1554                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1555                                 "pipeline port out sink");
1556                         return;
1557                 }
1558
1559                 p.type = PORT_OUT_SINK;
1560
1561                 p.dev_name = NULL;
1562
1563                 if (n_tokens == 7) {
1564                         p.sink.file_name = NULL;
1565                         p.sink.max_n_pkts = 0;
1566                 } else {
1567                         if (strcmp(tokens[7], "file") != 0) {
1568                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1569                                         "file");
1570                                 return;
1571                         }
1572
1573                         p.sink.file_name = tokens[8];
1574
1575                         if (strcmp(tokens[9], "pkts") != 0) {
1576                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1577                                 return;
1578                         }
1579
1580                         if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) {
1581                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1582                                 return;
1583                         }
1584                 }
1585         } else {
1586                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1587                 return;
1588         }
1589
1590         status = pipeline_port_out_create(pipeline_name, &p);
1591         if (status) {
1592                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1593                 return;
1594         }
1595 }
1596
1597 /**
1598  * pipeline <pipeline_name> table
1599  *      match
1600  *      acl
1601  *          ipv4 | ipv6
1602  *          offset <ip_header_offset>
1603  *          size <n_rules>
1604  *      | array
1605  *          offset <key_offset>
1606  *          size <n_keys>
1607  *      | hash
1608  *          ext | lru
1609  *          key <key_size>
1610  *          mask <key_mask>
1611  *          offset <key_offset>
1612  *          buckets <n_buckets>
1613  *          size <n_keys>
1614  *      | lpm
1615  *          ipv4 | ipv6
1616  *          offset <ip_header_offset>
1617  *          size <n_rules>
1618  *      | stub
1619  *  [action <table_action_profile_name>]
1620  */
1621 static void
1622 cmd_pipeline_table(char **tokens,
1623         uint32_t n_tokens,
1624         char *out,
1625         size_t out_size)
1626 {
1627         uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1628         struct table_params p;
1629         char *pipeline_name;
1630         uint32_t t0;
1631         int status;
1632
1633         if (n_tokens < 5) {
1634                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1635                 return;
1636         }
1637
1638         pipeline_name = tokens[1];
1639
1640         if (strcmp(tokens[2], "table") != 0) {
1641                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1642                 return;
1643         }
1644
1645         if (strcmp(tokens[3], "match") != 0) {
1646                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
1647                 return;
1648         }
1649
1650         t0 = 4;
1651         if (strcmp(tokens[t0], "acl") == 0) {
1652                 if (n_tokens < t0 + 6) {
1653                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1654                                 "pipeline table acl");
1655                         return;
1656                 }
1657
1658                 p.match_type = TABLE_ACL;
1659
1660                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
1661                         p.match.acl.ip_version = 1;
1662                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
1663                         p.match.acl.ip_version = 0;
1664                 else {
1665                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1666                                 "ipv4 or ipv6");
1667                         return;
1668                 }
1669
1670                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1671                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1672                         return;
1673                 }
1674
1675                 if (parser_read_uint32(&p.match.acl.ip_header_offset,
1676                         tokens[t0 + 3]) != 0) {
1677                         snprintf(out, out_size, MSG_ARG_INVALID,
1678                                 "ip_header_offset");
1679                         return;
1680                 }
1681
1682                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1683                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1684                         return;
1685                 }
1686
1687                 if (parser_read_uint32(&p.match.acl.n_rules,
1688                         tokens[t0 + 5]) != 0) {
1689                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1690                         return;
1691                 }
1692
1693                 t0 += 6;
1694         } else if (strcmp(tokens[t0], "array") == 0) {
1695                 if (n_tokens < t0 + 5) {
1696                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1697                                 "pipeline table array");
1698                         return;
1699                 }
1700
1701                 p.match_type = TABLE_ARRAY;
1702
1703                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1704                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1705                         return;
1706                 }
1707
1708                 if (parser_read_uint32(&p.match.array.key_offset,
1709                         tokens[t0 + 2]) != 0) {
1710                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1711                         return;
1712                 }
1713
1714                 if (strcmp(tokens[t0 + 3], "size") != 0) {
1715                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1716                         return;
1717                 }
1718
1719                 if (parser_read_uint32(&p.match.array.n_keys,
1720                         tokens[t0 + 4]) != 0) {
1721                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1722                         return;
1723                 }
1724
1725                 t0 += 5;
1726         } else if (strcmp(tokens[t0], "hash") == 0) {
1727                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
1728
1729                 if (n_tokens < t0 + 12) {
1730                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1731                                 "pipeline table hash");
1732                         return;
1733                 }
1734
1735                 p.match_type = TABLE_HASH;
1736
1737                 if (strcmp(tokens[t0 + 1], "ext") == 0)
1738                         p.match.hash.extendable_bucket = 1;
1739                 else if (strcmp(tokens[t0 + 1], "lru") == 0)
1740                         p.match.hash.extendable_bucket = 0;
1741                 else {
1742                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1743                                 "ext or lru");
1744                         return;
1745                 }
1746
1747                 if (strcmp(tokens[t0 + 2], "key") != 0) {
1748                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
1749                         return;
1750                 }
1751
1752                 if ((parser_read_uint32(&p.match.hash.key_size,
1753                         tokens[t0 + 3]) != 0) ||
1754                         (p.match.hash.key_size == 0) ||
1755                         (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
1756                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
1757                         return;
1758                 }
1759
1760                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
1761                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1762                         return;
1763                 }
1764
1765                 if ((parse_hex_string(tokens[t0 + 5],
1766                         key_mask, &key_mask_size) != 0) ||
1767                         (key_mask_size != p.match.hash.key_size)) {
1768                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1769                         return;
1770                 }
1771                 p.match.hash.key_mask = key_mask;
1772
1773                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
1774                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1775                         return;
1776                 }
1777
1778                 if (parser_read_uint32(&p.match.hash.key_offset,
1779                         tokens[t0 + 7]) != 0) {
1780                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1781                         return;
1782                 }
1783
1784                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
1785                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
1786                         return;
1787                 }
1788
1789                 if (parser_read_uint32(&p.match.hash.n_buckets,
1790                         tokens[t0 + 9]) != 0) {
1791                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
1792                         return;
1793                 }
1794
1795                 if (strcmp(tokens[t0 + 10], "size") != 0) {
1796                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1797                         return;
1798                 }
1799
1800                 if (parser_read_uint32(&p.match.hash.n_keys,
1801                         tokens[t0 + 11]) != 0) {
1802                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1803                         return;
1804                 }
1805
1806                 t0 += 12;
1807         } else if (strcmp(tokens[t0], "lpm") == 0) {
1808                 if (n_tokens < t0 + 6) {
1809                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1810                                 "pipeline table lpm");
1811                         return;
1812                 }
1813
1814                 p.match_type = TABLE_LPM;
1815
1816                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
1817                         p.match.lpm.key_size = 4;
1818                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
1819                         p.match.lpm.key_size = 16;
1820                 else {
1821                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1822                                 "ipv4 or ipv6");
1823                         return;
1824                 }
1825
1826                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1827                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1828                         return;
1829                 }
1830
1831                 if (parser_read_uint32(&p.match.lpm.key_offset,
1832                         tokens[t0 + 3]) != 0) {
1833                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1834                         return;
1835                 }
1836
1837                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1838                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1839                         return;
1840                 }
1841
1842                 if (parser_read_uint32(&p.match.lpm.n_rules,
1843                         tokens[t0 + 5]) != 0) {
1844                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1845                         return;
1846                 }
1847
1848                 t0 += 6;
1849         } else if (strcmp(tokens[t0], "stub") == 0) {
1850                 if (n_tokens < t0 + 1) {
1851                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1852                                 "pipeline table stub");
1853                         return;
1854                 }
1855
1856                 p.match_type = TABLE_STUB;
1857
1858                 t0 += 1;
1859         } else {
1860                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1861                 return;
1862         }
1863
1864         p.action_profile_name = NULL;
1865         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1866                 if (n_tokens < t0 + 2) {
1867                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1868                         return;
1869                 }
1870
1871                 p.action_profile_name = tokens[t0 + 1];
1872
1873                 t0 += 2;
1874         }
1875
1876         if (n_tokens > t0) {
1877                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1878                 return;
1879         }
1880
1881         status = pipeline_table_create(pipeline_name, &p);
1882         if (status) {
1883                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1884                 return;
1885         }
1886 }
1887
1888 /**
1889  * pipeline <pipeline_name> port in <port_id> table <table_id>
1890  */
1891 static void
1892 cmd_pipeline_port_in_table(char **tokens,
1893         uint32_t n_tokens,
1894         char *out,
1895         size_t out_size)
1896 {
1897         char *pipeline_name;
1898         uint32_t port_id, table_id;
1899         int status;
1900
1901         if (n_tokens != 7) {
1902                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1903                 return;
1904         }
1905
1906         pipeline_name = tokens[1];
1907
1908         if (strcmp(tokens[2], "port") != 0) {
1909                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1910                 return;
1911         }
1912
1913         if (strcmp(tokens[3], "in") != 0) {
1914                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1915                 return;
1916         }
1917
1918         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
1919                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1920                 return;
1921         }
1922
1923         if (strcmp(tokens[5], "table") != 0) {
1924                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1925                 return;
1926         }
1927
1928         if (parser_read_uint32(&table_id, tokens[6]) != 0) {
1929                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
1930                 return;
1931         }
1932
1933         status = pipeline_port_in_connect_to_table(pipeline_name,
1934                 port_id,
1935                 table_id);
1936         if (status) {
1937                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1938                 return;
1939         }
1940 }
1941
1942 /**
1943  * pipeline <pipeline_name> port in <port_id> stats read [clear]
1944  */
1945
1946 #define MSG_PIPELINE_PORT_IN_STATS                         \
1947         "Pkts in: %" PRIu64 "\n"                           \
1948         "Pkts dropped by AH: %" PRIu64 "\n"                \
1949         "Pkts dropped by other: %" PRIu64 "\n"
1950
1951 static void
1952 cmd_pipeline_port_in_stats(char **tokens,
1953         uint32_t n_tokens,
1954         char *out,
1955         size_t out_size)
1956 {
1957         struct rte_pipeline_port_in_stats stats;
1958         char *pipeline_name;
1959         uint32_t port_id;
1960         int clear, status;
1961
1962         if ((n_tokens != 7) && (n_tokens != 8)) {
1963                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1964                 return;
1965         }
1966
1967         pipeline_name = tokens[1];
1968
1969         if (strcmp(tokens[2], "port") != 0) {
1970                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1971                 return;
1972         }
1973
1974         if (strcmp(tokens[3], "in") != 0) {
1975                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1976                 return;
1977         }
1978
1979         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
1980                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1981                 return;
1982         }
1983
1984         if (strcmp(tokens[5], "stats") != 0) {
1985                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1986                 return;
1987         }
1988
1989         if (strcmp(tokens[6], "read") != 0) {
1990                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
1991                 return;
1992         }
1993
1994         clear = 0;
1995         if (n_tokens == 8) {
1996                 if (strcmp(tokens[7], "clear") != 0) {
1997                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
1998                         return;
1999                 }
2000
2001                 clear = 1;
2002         }
2003
2004         status = pipeline_port_in_stats_read(pipeline_name,
2005                 port_id,
2006                 &stats,
2007                 clear);
2008         if (status) {
2009                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2010                 return;
2011         }
2012
2013         snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
2014                 stats.stats.n_pkts_in,
2015                 stats.n_pkts_dropped_by_ah,
2016                 stats.stats.n_pkts_drop);
2017 }
2018
2019 /**
2020  * pipeline <pipeline_name> port in <port_id> enable
2021  */
2022 static void
2023 cmd_pipeline_port_in_enable(char **tokens,
2024         uint32_t n_tokens,
2025         char *out,
2026         size_t out_size)
2027 {
2028         char *pipeline_name;
2029         uint32_t port_id;
2030         int status;
2031
2032         if (n_tokens != 6) {
2033                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2034                 return;
2035         }
2036
2037         pipeline_name = tokens[1];
2038
2039         if (strcmp(tokens[2], "port") != 0) {
2040                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2041                 return;
2042         }
2043
2044         if (strcmp(tokens[3], "in") != 0) {
2045                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2046                 return;
2047         }
2048
2049         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2050                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2051                 return;
2052         }
2053
2054         if (strcmp(tokens[5], "enable") != 0) {
2055                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2056                 return;
2057         }
2058
2059         status = pipeline_port_in_enable(pipeline_name, port_id);
2060         if (status) {
2061                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2062                 return;
2063         }
2064 }
2065
2066 /**
2067  * pipeline <pipeline_name> port in <port_id> disable
2068  */
2069 static void
2070 cmd_pipeline_port_in_disable(char **tokens,
2071         uint32_t n_tokens,
2072         char *out,
2073         size_t out_size)
2074 {
2075         char *pipeline_name;
2076         uint32_t port_id;
2077         int status;
2078
2079         if (n_tokens != 6) {
2080                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2081                 return;
2082         }
2083
2084         pipeline_name = tokens[1];
2085
2086         if (strcmp(tokens[2], "port") != 0) {
2087                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2088                 return;
2089         }
2090
2091         if (strcmp(tokens[3], "in") != 0) {
2092                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2093                 return;
2094         }
2095
2096         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2097                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2098                 return;
2099         }
2100
2101         if (strcmp(tokens[5], "disable") != 0) {
2102                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2103                 return;
2104         }
2105
2106         status = pipeline_port_in_disable(pipeline_name, port_id);
2107         if (status) {
2108                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2109                 return;
2110         }
2111 }
2112
2113 /**
2114  * pipeline <pipeline_name> port out <port_id> stats read [clear]
2115  */
2116 #define MSG_PIPELINE_PORT_OUT_STATS                        \
2117         "Pkts in: %" PRIu64 "\n"                           \
2118         "Pkts dropped by AH: %" PRIu64 "\n"                \
2119         "Pkts dropped by other: %" PRIu64 "\n"
2120
2121 static void
2122 cmd_pipeline_port_out_stats(char **tokens,
2123         uint32_t n_tokens,
2124         char *out,
2125         size_t out_size)
2126 {
2127         struct rte_pipeline_port_out_stats stats;
2128         char *pipeline_name;
2129         uint32_t port_id;
2130         int clear, status;
2131
2132         if ((n_tokens != 7) && (n_tokens != 8)) {
2133                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2134                 return;
2135         }
2136
2137         pipeline_name = tokens[1];
2138
2139         if (strcmp(tokens[2], "port") != 0) {
2140                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2141                 return;
2142         }
2143
2144         if (strcmp(tokens[3], "out") != 0) {
2145                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2146                 return;
2147         }
2148
2149         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2150                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2151                 return;
2152         }
2153
2154         if (strcmp(tokens[5], "stats") != 0) {
2155                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2156                 return;
2157         }
2158
2159         if (strcmp(tokens[6], "read") != 0) {
2160                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2161                 return;
2162         }
2163
2164         clear = 0;
2165         if (n_tokens == 8) {
2166                 if (strcmp(tokens[7], "clear") != 0) {
2167                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2168                         return;
2169                 }
2170
2171                 clear = 1;
2172         }
2173
2174         status = pipeline_port_out_stats_read(pipeline_name,
2175                 port_id,
2176                 &stats,
2177                 clear);
2178         if (status) {
2179                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2180                 return;
2181         }
2182
2183         snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
2184                 stats.stats.n_pkts_in,
2185                 stats.n_pkts_dropped_by_ah,
2186                 stats.stats.n_pkts_drop);
2187 }
2188
2189 /**
2190  * pipeline <pipeline_name> table <table_id> stats read [clear]
2191  */
2192 #define MSG_PIPELINE_TABLE_STATS                                     \
2193         "Pkts in: %" PRIu64 "\n"                                     \
2194         "Pkts in with lookup miss: %" PRIu64 "\n"                    \
2195         "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
2196         "Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
2197         "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
2198         "Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
2199
2200 static void
2201 cmd_pipeline_table_stats(char **tokens,
2202         uint32_t n_tokens,
2203         char *out,
2204         size_t out_size)
2205 {
2206         struct rte_pipeline_table_stats stats;
2207         char *pipeline_name;
2208         uint32_t table_id;
2209         int clear, status;
2210
2211         if ((n_tokens != 6) && (n_tokens != 7)) {
2212                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2213                 return;
2214         }
2215
2216         pipeline_name = tokens[1];
2217
2218         if (strcmp(tokens[2], "table") != 0) {
2219                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2220                 return;
2221         }
2222
2223         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
2224                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2225                 return;
2226         }
2227
2228         if (strcmp(tokens[4], "stats") != 0) {
2229                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2230                 return;
2231         }
2232
2233         if (strcmp(tokens[5], "read") != 0) {
2234                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2235                 return;
2236         }
2237
2238         clear = 0;
2239         if (n_tokens == 7) {
2240                 if (strcmp(tokens[6], "clear") != 0) {
2241                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2242                         return;
2243                 }
2244
2245                 clear = 1;
2246         }
2247
2248         status = pipeline_table_stats_read(pipeline_name,
2249                 table_id,
2250                 &stats,
2251                 clear);
2252         if (status) {
2253                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2254                 return;
2255         }
2256
2257         snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
2258                 stats.stats.n_pkts_in,
2259                 stats.stats.n_pkts_lookup_miss,
2260                 stats.n_pkts_dropped_by_lkp_hit_ah,
2261                 stats.n_pkts_dropped_lkp_hit,
2262                 stats.n_pkts_dropped_by_lkp_miss_ah,
2263                 stats.n_pkts_dropped_lkp_miss);
2264 }
2265
2266 /**
2267  * <match> ::=
2268  *
2269  * match
2270  *    acl
2271  *       priority <priority>
2272  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
2273  *       <sp0> <sp1> <dp0> <dp1> <proto>
2274  *    | array
2275  *       pos
2276  *    | hash
2277  *       raw <key>
2278  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2279  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2280  *       | ipv4_addr <addr>
2281  *       | ipv6_addr <addr>
2282  *       | qinq <svlan> <cvlan>
2283  *    | lpm
2284  *       ipv4 | ipv6 <addr> <depth>
2285  */
2286 struct pkt_key_qinq {
2287         uint16_t ethertype_svlan;
2288         uint16_t svlan;
2289         uint16_t ethertype_cvlan;
2290         uint16_t cvlan;
2291 } __attribute__((__packed__));
2292
2293 struct pkt_key_ipv4_5tuple {
2294         uint8_t time_to_live;
2295         uint8_t proto;
2296         uint16_t hdr_checksum;
2297         uint32_t sa;
2298         uint32_t da;
2299         uint16_t sp;
2300         uint16_t dp;
2301 } __attribute__((__packed__));
2302
2303 struct pkt_key_ipv6_5tuple {
2304         uint16_t payload_length;
2305         uint8_t proto;
2306         uint8_t hop_limit;
2307         uint8_t sa[16];
2308         uint8_t da[16];
2309         uint16_t sp;
2310         uint16_t dp;
2311 } __attribute__((__packed__));
2312
2313 struct pkt_key_ipv4_addr {
2314         uint32_t addr;
2315 } __attribute__((__packed__));
2316
2317 struct pkt_key_ipv6_addr {
2318         uint8_t addr[16];
2319 } __attribute__((__packed__));
2320
2321 static uint32_t
2322 parse_match(char **tokens,
2323         uint32_t n_tokens,
2324         char *out,
2325         size_t out_size,
2326         struct table_rule_match *m)
2327 {
2328         memset(m, 0, sizeof(*m));
2329
2330         if (n_tokens < 2)
2331                 return 0;
2332
2333         if (strcmp(tokens[0], "match") != 0) {
2334                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2335                 return 0;
2336         }
2337
2338         if (strcmp(tokens[1], "acl") == 0) {
2339                 if (n_tokens < 14) {
2340                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2341                         return 0;
2342                 }
2343
2344                 m->match_type = TABLE_ACL;
2345
2346                 if (strcmp(tokens[2], "priority") != 0) {
2347                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
2348                         return 0;
2349                 }
2350
2351                 if (parser_read_uint32(&m->match.acl.priority,
2352                         tokens[3]) != 0) {
2353                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
2354                         return 0;
2355                 }
2356
2357                 if (strcmp(tokens[4], "ipv4") == 0) {
2358                         struct in_addr saddr, daddr;
2359
2360                         m->match.acl.ip_version = 1;
2361
2362                         if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
2363                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2364                                 return 0;
2365                         }
2366                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
2367
2368                         if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
2369                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2370                                 return 0;
2371                         }
2372                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
2373                 } else if (strcmp(tokens[4], "ipv6") == 0) {
2374                         struct in6_addr saddr, daddr;
2375
2376                         m->match.acl.ip_version = 0;
2377
2378                         if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
2379                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2380                                 return 0;
2381                         }
2382                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2383
2384                         if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2385                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2386                                 return 0;
2387                         }
2388                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
2389                 } else {
2390                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2391                                 "ipv4 or ipv6");
2392                         return 0;
2393                 }
2394
2395                 if (parser_read_uint32(&m->match.acl.sa_depth,
2396                         tokens[6]) != 0) {
2397                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
2398                         return 0;
2399                 }
2400
2401                 if (parser_read_uint32(&m->match.acl.da_depth,
2402                         tokens[8]) != 0) {
2403                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
2404                         return 0;
2405                 }
2406
2407                 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
2408                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
2409                         return 0;
2410                 }
2411
2412                 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
2413                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
2414                         return 0;
2415                 }
2416
2417                 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
2418                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
2419                         return 0;
2420                 }
2421
2422                 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
2423                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
2424                         return 0;
2425                 }
2426
2427                 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
2428                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
2429                         return 0;
2430                 }
2431
2432                 m->match.acl.proto_mask = 0xff;
2433
2434                 return 14;
2435         } /* acl */
2436
2437         if (strcmp(tokens[1], "array") == 0) {
2438                 if (n_tokens < 3) {
2439                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2440                         return 0;
2441                 }
2442
2443                 m->match_type = TABLE_ARRAY;
2444
2445                 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
2446                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
2447                         return 0;
2448                 }
2449
2450                 return 3;
2451         } /* array */
2452
2453         if (strcmp(tokens[1], "hash") == 0) {
2454                 if (n_tokens < 3) {
2455                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2456                         return 0;
2457                 }
2458
2459                 m->match_type = TABLE_HASH;
2460
2461                 if (strcmp(tokens[2], "raw") == 0) {
2462                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
2463
2464                         if (n_tokens < 4) {
2465                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2466                                         tokens[0]);
2467                                 return 0;
2468                         }
2469
2470                         if (parse_hex_string(tokens[3],
2471                                 m->match.hash.key, &key_size) != 0) {
2472                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
2473                                 return 0;
2474                         }
2475
2476                         return 4;
2477                 } /* hash raw */
2478
2479                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
2480                         struct pkt_key_ipv4_5tuple *ipv4 =
2481                                 (struct pkt_key_ipv4_5tuple *) m->match.hash.key;
2482                         struct in_addr saddr, daddr;
2483                         uint16_t sp, dp;
2484                         uint8_t proto;
2485
2486                         if (n_tokens < 8) {
2487                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2488                                         tokens[0]);
2489                                 return 0;
2490                         }
2491
2492                         if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
2493                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2494                                 return 0;
2495                         }
2496
2497                         if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
2498                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2499                                 return 0;
2500                         }
2501
2502                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2503                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2504                                 return 0;
2505                         }
2506
2507                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2508                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2509                                 return 0;
2510                         }
2511
2512                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2513                                 snprintf(out, out_size, MSG_ARG_INVALID,
2514                                         "proto");
2515                                 return 0;
2516                         }
2517
2518                         ipv4->sa = saddr.s_addr;
2519                         ipv4->da = daddr.s_addr;
2520                         ipv4->sp = rte_cpu_to_be_16(sp);
2521                         ipv4->dp = rte_cpu_to_be_16(dp);
2522                         ipv4->proto = proto;
2523
2524                         return 8;
2525                 } /* hash ipv4_5tuple */
2526
2527                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
2528                         struct pkt_key_ipv6_5tuple *ipv6 =
2529                                 (struct pkt_key_ipv6_5tuple *) m->match.hash.key;
2530                         struct in6_addr saddr, daddr;
2531                         uint16_t sp, dp;
2532                         uint8_t proto;
2533
2534                         if (n_tokens < 8) {
2535                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2536                                         tokens[0]);
2537                                 return 0;
2538                         }
2539
2540                         if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
2541                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2542                                 return 0;
2543                         }
2544
2545                         if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
2546                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2547                                 return 0;
2548                         }
2549
2550                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2551                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2552                                 return 0;
2553                         }
2554
2555                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2556                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2557                                 return 0;
2558                         }
2559
2560                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2561                                 snprintf(out, out_size, MSG_ARG_INVALID,
2562                                         "proto");
2563                                 return 0;
2564                         }
2565
2566                         memcpy(ipv6->sa, saddr.s6_addr, 16);
2567                         memcpy(ipv6->da, daddr.s6_addr, 16);
2568                         ipv6->sp = rte_cpu_to_be_16(sp);
2569                         ipv6->dp = rte_cpu_to_be_16(dp);
2570                         ipv6->proto = proto;
2571
2572                         return 8;
2573                 } /* hash ipv6_5tuple */
2574
2575                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
2576                         struct pkt_key_ipv4_addr *ipv4_addr =
2577                                 (struct pkt_key_ipv4_addr *) m->match.hash.key;
2578                         struct in_addr addr;
2579
2580                         if (n_tokens < 4) {
2581                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2582                                         tokens[0]);
2583                                 return 0;
2584                         }
2585
2586                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2587                                 snprintf(out, out_size, MSG_ARG_INVALID,
2588                                         "addr");
2589                                 return 0;
2590                         }
2591
2592                         ipv4_addr->addr = addr.s_addr;
2593
2594                         return 4;
2595                 } /* hash ipv4_addr */
2596
2597                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
2598                         struct pkt_key_ipv6_addr *ipv6_addr =
2599                                 (struct pkt_key_ipv6_addr *) m->match.hash.key;
2600                         struct in6_addr addr;
2601
2602                         if (n_tokens < 4) {
2603                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2604                                         tokens[0]);
2605                                 return 0;
2606                         }
2607
2608                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2609                                 snprintf(out, out_size, MSG_ARG_INVALID,
2610                                         "addr");
2611                                 return 0;
2612                         }
2613
2614                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
2615
2616                         return 4;
2617                 } /* hash ipv6_5tuple */
2618
2619                 if (strcmp(tokens[2], "qinq") == 0) {
2620                         struct pkt_key_qinq *qinq =
2621                                 (struct pkt_key_qinq *) m->match.hash.key;
2622                         uint16_t svlan, cvlan;
2623
2624                         if (n_tokens < 5) {
2625                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2626                                         tokens[0]);
2627                                 return 0;
2628                         }
2629
2630                         if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
2631                                 (svlan > 0xFFF)) {
2632                                 snprintf(out, out_size, MSG_ARG_INVALID,
2633                                         "svlan");
2634                                 return 0;
2635                         }
2636
2637                         if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
2638                                 (cvlan > 0xFFF)) {
2639                                 snprintf(out, out_size, MSG_ARG_INVALID,
2640                                         "cvlan");
2641                                 return 0;
2642                         }
2643
2644                         qinq->svlan = rte_cpu_to_be_16(svlan);
2645                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
2646
2647                         return 5;
2648                 } /* hash qinq */
2649
2650                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2651                 return 0;
2652         } /* hash */
2653
2654         if (strcmp(tokens[1], "lpm") == 0) {
2655                 if (n_tokens < 5) {
2656                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2657                         return 0;
2658                 }
2659
2660                 m->match_type = TABLE_LPM;
2661
2662                 if (strcmp(tokens[2], "ipv4") == 0) {
2663                         struct in_addr addr;
2664
2665                         m->match.lpm.ip_version = 1;
2666
2667                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2668                                 snprintf(out, out_size, MSG_ARG_INVALID,
2669                                         "addr");
2670                                 return 0;
2671                         }
2672
2673                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
2674                 } else if (strcmp(tokens[2], "ipv6") == 0) {
2675                         struct in6_addr addr;
2676
2677                         m->match.lpm.ip_version = 0;
2678
2679                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2680                                 snprintf(out, out_size, MSG_ARG_INVALID,
2681                                         "addr");
2682                                 return 0;
2683                         }
2684
2685                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
2686                 } else {
2687                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2688                                 "ipv4 or ipv6");
2689                         return 0;
2690                 }
2691
2692                 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
2693                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
2694                         return 0;
2695                 }
2696
2697                 return 5;
2698         } /* lpm */
2699
2700         snprintf(out, out_size, MSG_ARG_MISMATCH,
2701                 "acl or array or hash or lpm");
2702         return 0;
2703 }
2704
2705 /**
2706  * table_action ::=
2707  *
2708  * action
2709  *    fwd
2710  *       drop
2711  *       | port <port_id>
2712  *       | meta
2713  *       | table <table_id>
2714  *    [balance <out0> ... <out7>]
2715  *    [meter
2716  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2717  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2718  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2719  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
2720  *    [tm subport <subport_id> pipe <pipe_id>]
2721  *    [encap
2722  *       ether <da> <sa>
2723  *       | vlan <da> <sa> <pcp> <dei> <vid>
2724  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
2725  *       | mpls unicast | multicast
2726  *          <da> <sa>
2727  *          label0 <label> <tc> <ttl>
2728  *          [label1 <label> <tc> <ttl>
2729  *          [label2 <label> <tc> <ttl>
2730  *          [label3 <label> <tc> <ttl>]]]
2731  *       | pppoe <da> <sa> <session_id>]
2732  *    [nat ipv4 | ipv6 <addr> <port>]
2733  *    [ttl dec | keep]
2734  *    [stats]
2735  *    [time]
2736  *
2737  * where:
2738  *    <pa> ::= g | y | r | drop
2739  */
2740 static uint32_t
2741 parse_table_action_fwd(char **tokens,
2742         uint32_t n_tokens,
2743         struct table_rule_action *a)
2744 {
2745         if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
2746                 return 0;
2747
2748         tokens++;
2749         n_tokens--;
2750
2751         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
2752                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
2753                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2754                 return 1 + 1;
2755         }
2756
2757         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
2758                 uint32_t id;
2759
2760                 if ((n_tokens < 2) ||
2761                         parser_read_uint32(&id, tokens[1]))
2762                         return 0;
2763
2764                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
2765                 a->fwd.id = id;
2766                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2767                 return 1 + 2;
2768         }
2769
2770         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
2771                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
2772                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2773                 return 1 + 1;
2774         }
2775
2776         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
2777                 uint32_t id;
2778
2779                 if ((n_tokens < 2) ||
2780                         parser_read_uint32(&id, tokens[1]))
2781                         return 0;
2782
2783                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
2784                 a->fwd.id = id;
2785                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2786                 return 1 + 2;
2787         }
2788
2789         return 0;
2790 }
2791
2792 static int
2793 parse_policer_action(char *token, enum rte_table_action_policer *a)
2794 {
2795         if (strcmp(token, "g") == 0) {
2796                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
2797                 return 0;
2798         }
2799
2800         if (strcmp(token, "y") == 0) {
2801                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
2802                 return 0;
2803         }
2804
2805         if (strcmp(token, "r") == 0) {
2806                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
2807                 return 0;
2808         }
2809
2810         if (strcmp(token, "drop") == 0) {
2811                 *a = RTE_TABLE_ACTION_POLICER_DROP;
2812                 return 0;
2813         }
2814
2815         return -1;
2816 }
2817
2818 static uint32_t
2819 parse_table_action_meter_tc(char **tokens,
2820         uint32_t n_tokens,
2821         struct rte_table_action_mtr_tc_params *mtr)
2822 {
2823         if ((n_tokens < 9) ||
2824                 strcmp(tokens[0], "meter") ||
2825                 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
2826                 strcmp(tokens[2], "policer") ||
2827                 strcmp(tokens[3], "g") ||
2828                 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
2829                 strcmp(tokens[5], "y") ||
2830                 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
2831                 strcmp(tokens[7], "r") ||
2832                 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
2833                 return 0;
2834
2835         return 9;
2836 }
2837
2838 static uint32_t
2839 parse_table_action_meter(char **tokens,
2840         uint32_t n_tokens,
2841         struct table_rule_action *a)
2842 {
2843         if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
2844                 return 0;
2845
2846         tokens++;
2847         n_tokens--;
2848
2849         if ((n_tokens < 10) ||
2850                 strcmp(tokens[0], "tc0") ||
2851                 (parse_table_action_meter_tc(tokens + 1,
2852                         n_tokens - 1,
2853                         &a->mtr.mtr[0]) == 0))
2854                 return 0;
2855
2856         tokens += 10;
2857         n_tokens -= 10;
2858
2859         if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
2860                 a->mtr.tc_mask = 1;
2861                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2862                 return 1 + 10;
2863         }
2864
2865         if ((n_tokens < 30) ||
2866                 (parse_table_action_meter_tc(tokens + 1,
2867                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
2868                 strcmp(tokens[10], "tc2") ||
2869                 (parse_table_action_meter_tc(tokens + 11,
2870                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
2871                 strcmp(tokens[20], "tc3") ||
2872                 (parse_table_action_meter_tc(tokens + 21,
2873                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
2874                 return 0;
2875
2876         a->mtr.tc_mask = 0xF;
2877         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2878         return 1 + 10 + 3 * 10;
2879 }
2880
2881 static uint32_t
2882 parse_table_action_tm(char **tokens,
2883         uint32_t n_tokens,
2884         struct table_rule_action *a)
2885 {
2886         uint32_t subport_id, pipe_id;
2887
2888         if ((n_tokens < 5) ||
2889                 strcmp(tokens[0], "tm") ||
2890                 strcmp(tokens[1], "subport") ||
2891                 parser_read_uint32(&subport_id, tokens[2]) ||
2892                 strcmp(tokens[3], "pipe") ||
2893                 parser_read_uint32(&pipe_id, tokens[4]))
2894                 return 0;
2895
2896         a->tm.subport_id = subport_id;
2897         a->tm.pipe_id = pipe_id;
2898         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
2899         return 5;
2900 }
2901
2902 static uint32_t
2903 parse_table_action_encap(char **tokens,
2904         uint32_t n_tokens,
2905         struct table_rule_action *a)
2906 {
2907         if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
2908                 return 0;
2909
2910         tokens++;
2911         n_tokens--;
2912
2913         /* ether */
2914         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
2915                 if ((n_tokens < 3) ||
2916                         parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
2917                         parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
2918                         return 0;
2919
2920                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
2921                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2922                 return 1 + 3;
2923         }
2924
2925         /* vlan */
2926         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
2927                 uint32_t pcp, dei, vid;
2928
2929                 if ((n_tokens < 6) ||
2930                         parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
2931                         parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
2932                         parser_read_uint32(&pcp, tokens[3]) ||
2933                         (pcp > 0x7) ||
2934                         parser_read_uint32(&dei, tokens[4]) ||
2935                         (dei > 0x1) ||
2936                         parser_read_uint32(&vid, tokens[5]) ||
2937                         (vid > 0xFFF))
2938                         return 0;
2939
2940                 a->encap.vlan.vlan.pcp = pcp & 0x7;
2941                 a->encap.vlan.vlan.dei = dei & 0x1;
2942                 a->encap.vlan.vlan.vid = vid & 0xFFF;
2943                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
2944                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2945                 return 1 + 6;
2946         }
2947
2948         /* qinq */
2949         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
2950                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
2951                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
2952
2953                 if ((n_tokens < 9) ||
2954                         parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
2955                         parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
2956                         parser_read_uint32(&svlan_pcp, tokens[3]) ||
2957                         (svlan_pcp > 0x7) ||
2958                         parser_read_uint32(&svlan_dei, tokens[4]) ||
2959                         (svlan_dei > 0x1) ||
2960                         parser_read_uint32(&svlan_vid, tokens[5]) ||
2961                         (svlan_vid > 0xFFF) ||
2962                         parser_read_uint32(&cvlan_pcp, tokens[6]) ||
2963                         (cvlan_pcp > 0x7) ||
2964                         parser_read_uint32(&cvlan_dei, tokens[7]) ||
2965                         (cvlan_dei > 0x1) ||
2966                         parser_read_uint32(&cvlan_vid, tokens[8]) ||
2967                         (cvlan_vid > 0xFFF))
2968                         return 0;
2969
2970                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
2971                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
2972                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
2973                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
2974                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
2975                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
2976                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
2977                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2978                 return 1 + 9;
2979         }
2980
2981         /* mpls */
2982         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
2983                 uint32_t label, tc, ttl;
2984
2985                 if (n_tokens < 8)
2986                         return 0;
2987
2988                 if (strcmp(tokens[1], "unicast") == 0)
2989                         a->encap.mpls.unicast = 1;
2990                 else if (strcmp(tokens[1], "multicast") == 0)
2991                         a->encap.mpls.unicast = 0;
2992                 else
2993                         return 0;
2994
2995                 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
2996                         parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
2997                         strcmp(tokens[4], "label0") ||
2998                         parser_read_uint32(&label, tokens[5]) ||
2999                         (label > 0xFFFFF) ||
3000                         parser_read_uint32(&tc, tokens[6]) ||
3001                         (tc > 0x7) ||
3002                         parser_read_uint32(&ttl, tokens[7]) ||
3003                         (ttl > 0x3F))
3004                         return 0;
3005
3006                 a->encap.mpls.mpls[0].label = label;
3007                 a->encap.mpls.mpls[0].tc = tc;
3008                 a->encap.mpls.mpls[0].ttl = ttl;
3009
3010                 tokens += 8;
3011                 n_tokens -= 8;
3012
3013                 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
3014                         a->encap.mpls.mpls_count = 1;
3015                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3016                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3017                         return 1 + 8;
3018                 }
3019
3020                 if ((n_tokens < 4) ||
3021                         parser_read_uint32(&label, tokens[1]) ||
3022                         (label > 0xFFFFF) ||
3023                         parser_read_uint32(&tc, tokens[2]) ||
3024                         (tc > 0x7) ||
3025                         parser_read_uint32(&ttl, tokens[3]) ||
3026                         (ttl > 0x3F))
3027                         return 0;
3028
3029                 a->encap.mpls.mpls[1].label = label;
3030                 a->encap.mpls.mpls[1].tc = tc;
3031                 a->encap.mpls.mpls[1].ttl = ttl;
3032
3033                 tokens += 4;
3034                 n_tokens -= 4;
3035
3036                 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
3037                         a->encap.mpls.mpls_count = 2;
3038                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3039                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3040                         return 1 + 8 + 4;
3041                 }
3042
3043                 if ((n_tokens < 4) ||
3044                         parser_read_uint32(&label, tokens[1]) ||
3045                         (label > 0xFFFFF) ||
3046                         parser_read_uint32(&tc, tokens[2]) ||
3047                         (tc > 0x7) ||
3048                         parser_read_uint32(&ttl, tokens[3]) ||
3049                         (ttl > 0x3F))
3050                         return 0;
3051
3052                 a->encap.mpls.mpls[2].label = label;
3053                 a->encap.mpls.mpls[2].tc = tc;
3054                 a->encap.mpls.mpls[2].ttl = ttl;
3055
3056                 tokens += 4;
3057                 n_tokens -= 4;
3058
3059                 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
3060                         a->encap.mpls.mpls_count = 3;
3061                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3062                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3063                         return 1 + 8 + 4 + 4;
3064                 }
3065
3066                 if ((n_tokens < 4) ||
3067                         parser_read_uint32(&label, tokens[1]) ||
3068                         (label > 0xFFFFF) ||
3069                         parser_read_uint32(&tc, tokens[2]) ||
3070                         (tc > 0x7) ||
3071                         parser_read_uint32(&ttl, tokens[3]) ||
3072                         (ttl > 0x3F))
3073                         return 0;
3074
3075                 a->encap.mpls.mpls[3].label = label;
3076                 a->encap.mpls.mpls[3].tc = tc;
3077                 a->encap.mpls.mpls[3].ttl = ttl;
3078
3079                 a->encap.mpls.mpls_count = 4;
3080                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3081                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3082                 return 1 + 8 + 4 + 4 + 4;
3083         }
3084
3085         /* pppoe */
3086         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3087                 if ((n_tokens < 4) ||
3088                         parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3089                         parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3090                         parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3091                                 tokens[3]))
3092                         return 0;
3093
3094                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3095                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3096                 return 1 + 4;
3097         }
3098
3099         return 0;
3100 }
3101
3102 static uint32_t
3103 parse_table_action_nat(char **tokens,
3104         uint32_t n_tokens,
3105         struct table_rule_action *a)
3106 {
3107         if ((n_tokens < 4) ||
3108                 strcmp(tokens[0], "nat"))
3109                 return 0;
3110
3111         if (strcmp(tokens[1], "ipv4") == 0) {
3112                 struct in_addr addr;
3113                 uint16_t port;
3114
3115                 if (parse_ipv4_addr(tokens[2], &addr) ||
3116                         parser_read_uint16(&port, tokens[3]))
3117                         return 0;
3118
3119                 a->nat.ip_version = 1;
3120                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3121                 a->nat.port = port;
3122                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3123                 return 4;
3124         }
3125
3126         if (strcmp(tokens[1], "ipv6") == 0) {
3127                 struct in6_addr addr;
3128                 uint16_t port;
3129
3130                 if (parse_ipv6_addr(tokens[2], &addr) ||
3131                         parser_read_uint16(&port, tokens[3]))
3132                         return 0;
3133
3134                 a->nat.ip_version = 0;
3135                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3136                 a->nat.port = port;
3137                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3138                 return 4;
3139         }
3140
3141         return 0;
3142 }
3143
3144 static uint32_t
3145 parse_table_action_ttl(char **tokens,
3146         uint32_t n_tokens,
3147         struct table_rule_action *a)
3148 {
3149         if ((n_tokens < 2) ||
3150                 strcmp(tokens[0], "ttl"))
3151                 return 0;
3152
3153         if (strcmp(tokens[1], "dec") == 0)
3154                 a->ttl.decrement = 1;
3155         else if (strcmp(tokens[1], "keep") == 0)
3156                 a->ttl.decrement = 0;
3157         else
3158                 return 0;
3159
3160         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
3161         return 2;
3162 }
3163
3164 static uint32_t
3165 parse_table_action_stats(char **tokens,
3166         uint32_t n_tokens,
3167         struct table_rule_action *a)
3168 {
3169         if ((n_tokens < 1) ||
3170                 strcmp(tokens[0], "stats"))
3171                 return 0;
3172
3173         a->stats.n_packets = 0;
3174         a->stats.n_bytes = 0;
3175         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
3176         return 1;
3177 }
3178
3179 static uint32_t
3180 parse_table_action_time(char **tokens,
3181         uint32_t n_tokens,
3182         struct table_rule_action *a)
3183 {
3184         if ((n_tokens < 1) ||
3185                 strcmp(tokens[0], "time"))
3186                 return 0;
3187
3188         a->time.time = rte_rdtsc();
3189         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
3190         return 1;
3191 }
3192
3193 static uint32_t
3194 parse_table_action(char **tokens,
3195         uint32_t n_tokens,
3196         char *out,
3197         size_t out_size,
3198         struct table_rule_action *a)
3199 {
3200         uint32_t n_tokens0 = n_tokens;
3201
3202         memset(a, 0, sizeof(*a));
3203
3204         if ((n_tokens < 2) ||
3205                 strcmp(tokens[0], "action"))
3206                 return 0;
3207
3208         tokens++;
3209         n_tokens--;
3210
3211         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
3212                 uint32_t n;
3213
3214                 n = parse_table_action_fwd(tokens, n_tokens, a);
3215                 if (n == 0) {
3216                         snprintf(out, out_size, MSG_ARG_INVALID,
3217                                 "action fwd");
3218                         return 0;
3219                 }
3220
3221                 tokens += n;
3222                 n_tokens -= n;
3223         }
3224
3225         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
3226                 uint32_t n;
3227
3228                 n = parse_table_action_meter(tokens, n_tokens, a);
3229                 if (n == 0) {
3230                         snprintf(out, out_size, MSG_ARG_INVALID,
3231                                 "action meter");
3232                         return 0;
3233                 }
3234
3235                 tokens += n;
3236                 n_tokens -= n;
3237         }
3238
3239         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
3240                 uint32_t n;
3241
3242                 n = parse_table_action_tm(tokens, n_tokens, a);
3243                 if (n == 0) {
3244                         snprintf(out, out_size, MSG_ARG_INVALID,
3245                                 "action tm");
3246                         return 0;
3247                 }
3248
3249                 tokens += n;
3250                 n_tokens -= n;
3251         }
3252
3253         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
3254                 uint32_t n;
3255
3256                 n = parse_table_action_encap(tokens, n_tokens, a);
3257                 if (n == 0) {
3258                         snprintf(out, out_size, MSG_ARG_INVALID,
3259                                 "action encap");
3260                         return 0;
3261                 }
3262
3263                 tokens += n;
3264                 n_tokens -= n;
3265         }
3266
3267         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
3268                 uint32_t n;
3269
3270                 n = parse_table_action_nat(tokens, n_tokens, a);
3271                 if (n == 0) {
3272                         snprintf(out, out_size, MSG_ARG_INVALID,
3273                                 "action nat");
3274                         return 0;
3275                 }
3276
3277                 tokens += n;
3278                 n_tokens -= n;
3279         }
3280
3281         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
3282                 uint32_t n;
3283
3284                 n = parse_table_action_ttl(tokens, n_tokens, a);
3285                 if (n == 0) {
3286                         snprintf(out, out_size, MSG_ARG_INVALID,
3287                                 "action ttl");
3288                         return 0;
3289                 }
3290
3291                 tokens += n;
3292                 n_tokens -= n;
3293         }
3294
3295         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
3296                 uint32_t n;
3297
3298                 n = parse_table_action_stats(tokens, n_tokens, a);
3299                 if (n == 0) {
3300                         snprintf(out, out_size, MSG_ARG_INVALID,
3301                                 "action stats");
3302                         return 0;
3303                 }
3304
3305                 tokens += n;
3306                 n_tokens -= n;
3307         }
3308
3309         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
3310                 uint32_t n;
3311
3312                 n = parse_table_action_time(tokens, n_tokens, a);
3313                 if (n == 0) {
3314                         snprintf(out, out_size, MSG_ARG_INVALID,
3315                                 "action time");
3316                         return 0;
3317                 }
3318
3319                 tokens += n;
3320                 n_tokens -= n;
3321         }
3322
3323         if (n_tokens0 - n_tokens == 1) {
3324                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3325                 return 0;
3326         }
3327
3328         return n_tokens0 - n_tokens;
3329 }
3330
3331 /**
3332  * pipeline <pipeline_name> table <table_id> rule add
3333  *    match <match>
3334  *    action <table_action>
3335  */
3336 static void
3337 cmd_pipeline_table_rule_add(char **tokens,
3338         uint32_t n_tokens,
3339         char *out,
3340         size_t out_size)
3341 {
3342         struct table_rule_match m;
3343         struct table_rule_action a;
3344         char *pipeline_name;
3345         void *data;
3346         uint32_t table_id, t0, n_tokens_parsed;
3347         int status;
3348
3349         if (n_tokens < 8) {
3350                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3351                 return;
3352         }
3353
3354         pipeline_name = tokens[1];
3355
3356         if (strcmp(tokens[2], "table") != 0) {
3357                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3358                 return;
3359         }
3360
3361         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3362                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3363                 return;
3364         }
3365
3366         if (strcmp(tokens[4], "rule") != 0) {
3367                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3368                 return;
3369         }
3370
3371         if (strcmp(tokens[5], "add") != 0) {
3372                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3373                 return;
3374         }
3375
3376         t0 = 6;
3377
3378         /* match */
3379         n_tokens_parsed = parse_match(tokens + t0,
3380                 n_tokens - t0,
3381                 out,
3382                 out_size,
3383                 &m);
3384         if (n_tokens_parsed == 0)
3385                 return;
3386         t0 += n_tokens_parsed;
3387
3388         /* action */
3389         n_tokens_parsed = parse_table_action(tokens + t0,
3390                 n_tokens - t0,
3391                 out,
3392                 out_size,
3393                 &a);
3394         if (n_tokens_parsed == 0)
3395                 return;
3396         t0 += n_tokens_parsed;
3397
3398         if (t0 != n_tokens) {
3399                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
3400                 return;
3401         }
3402
3403         status = pipeline_table_rule_add(pipeline_name, table_id,
3404                 &m, &a, &data);
3405         if (status) {
3406                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3407                 return;
3408         }
3409 }
3410
3411 /**
3412  * pipeline <pipeline_name> table <table_id> rule add
3413  *    match
3414  *       default
3415  *    action
3416  *       fwd
3417  *          drop
3418  *          | port <port_id>
3419  *          | meta
3420  *          | table <table_id>
3421  */
3422 static void
3423 cmd_pipeline_table_rule_add_default(char **tokens,
3424         uint32_t n_tokens,
3425         char *out,
3426         size_t out_size)
3427 {
3428         struct table_rule_action action;
3429         void *data;
3430         char *pipeline_name;
3431         uint32_t table_id;
3432         int status;
3433
3434         if ((n_tokens != 11) && (n_tokens != 12)) {
3435                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3436                 return;
3437         }
3438
3439         pipeline_name = tokens[1];
3440
3441         if (strcmp(tokens[2], "table") != 0) {
3442                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3443                 return;
3444         }
3445
3446         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3447                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3448                 return;
3449         }
3450
3451         if (strcmp(tokens[4], "rule") != 0) {
3452                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3453                 return;
3454         }
3455
3456         if (strcmp(tokens[5], "add") != 0) {
3457                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3458                 return;
3459         }
3460
3461         if (strcmp(tokens[6], "match") != 0) {
3462                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3463                 return;
3464         }
3465
3466         if (strcmp(tokens[7], "default") != 0) {
3467                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3468                 return;
3469         }
3470
3471         if (strcmp(tokens[8], "action") != 0) {
3472                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3473                 return;
3474         }
3475
3476         if (strcmp(tokens[9], "fwd") != 0) {
3477                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
3478                 return;
3479         }
3480
3481         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
3482
3483         if (strcmp(tokens[10], "drop") == 0) {
3484                 if (n_tokens != 11) {
3485                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3486                         return;
3487                 }
3488
3489                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
3490         } else if (strcmp(tokens[10], "port") == 0) {
3491                 uint32_t id;
3492
3493                 if (n_tokens != 12) {
3494                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3495                         return;
3496                 }
3497
3498                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3499                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
3500                         return;
3501                 }
3502
3503                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
3504                 action.fwd.id = id;
3505         } else if (strcmp(tokens[10], "meta") == 0) {
3506                 if (n_tokens != 11) {
3507                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3508                         return;
3509                 }
3510
3511                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3512         } else if (strcmp(tokens[10], "table") == 0) {
3513                 uint32_t id;
3514
3515                 if (n_tokens != 12) {
3516                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3517                         return;
3518                 }
3519
3520                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3521                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3522                         return;
3523                 }
3524
3525                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
3526                 action.fwd.id = id;
3527         } else {
3528                 snprintf(out, out_size, MSG_ARG_INVALID,
3529                         "drop or port or meta or table");
3530                 return;
3531         }
3532
3533         status = pipeline_table_rule_add_default(pipeline_name,
3534                 table_id,
3535                 &action,
3536                 &data);
3537         if (status) {
3538                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3539                 return;
3540         }
3541 }
3542
3543 /**
3544  * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>
3545  *
3546  * File <file_name>:
3547  * - line format: match <match> action <action>
3548  */
3549 static int
3550 cli_rule_file_process(const char *file_name,
3551         size_t line_len_max,
3552         struct table_rule_match *m,
3553         struct table_rule_action *a,
3554         uint32_t *n_rules,
3555         uint32_t *line_number,
3556         char *out,
3557         size_t out_size);
3558
3559 static void
3560 cmd_pipeline_table_rule_add_bulk(char **tokens,
3561         uint32_t n_tokens,
3562         char *out,
3563         size_t out_size)
3564 {
3565         struct table_rule_match *match;
3566         struct table_rule_action *action;
3567         void **data;
3568         char *pipeline_name, *file_name;
3569         uint32_t table_id, n_rules, n_rules_parsed, line_number;
3570         int status;
3571
3572         if (n_tokens != 9) {
3573                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3574                 return;
3575         }
3576
3577         pipeline_name = tokens[1];
3578
3579         if (strcmp(tokens[2], "table") != 0) {
3580                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3581                 return;
3582         }
3583
3584         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3585                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3586                 return;
3587         }
3588
3589         if (strcmp(tokens[4], "rule") != 0) {
3590                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3591                 return;
3592         }
3593
3594         if (strcmp(tokens[5], "add") != 0) {
3595                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3596                 return;
3597         }
3598
3599         if (strcmp(tokens[6], "bulk") != 0) {
3600                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
3601                 return;
3602         }
3603
3604         file_name = tokens[7];
3605
3606         if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
3607                 (n_rules == 0)) {
3608                 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
3609                 return;
3610         }
3611
3612         /* Memory allocation. */
3613         match = calloc(n_rules, sizeof(struct table_rule_match));
3614         action = calloc(n_rules, sizeof(struct table_rule_action));
3615         data = calloc(n_rules, sizeof(void *));
3616         if ((match == NULL) || (action == NULL) || (data == NULL)) {
3617                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
3618                 free(data);
3619                 free(action);
3620                 free(match);
3621                 return;
3622         }
3623
3624         /* Load rule file */
3625         n_rules_parsed = n_rules;
3626         status = cli_rule_file_process(file_name,
3627                 1024,
3628                 match,
3629                 action,
3630                 &n_rules_parsed,
3631                 &line_number,
3632                 out,
3633                 out_size);
3634         if (status) {
3635                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
3636                 free(data);
3637                 free(action);
3638                 free(match);
3639                 return;
3640         }
3641         if (n_rules_parsed != n_rules) {
3642                 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
3643                 free(data);
3644                 free(action);
3645                 free(match);
3646                 return;
3647         }
3648
3649         /* Rule bulk add */
3650         status = pipeline_table_rule_add_bulk(pipeline_name,
3651                 table_id,
3652                 match,
3653                 action,
3654                 data,
3655                 &n_rules);
3656         if (status) {
3657                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3658                 free(data);
3659                 free(action);
3660                 free(match);
3661                 return;
3662         }
3663
3664         /* Memory free */
3665         free(data);
3666         free(action);
3667         free(match);
3668 }
3669
3670 /**
3671  * pipeline <pipeline_name> table <table_id> rule delete
3672  *    match <match>
3673  */
3674 static void
3675 cmd_pipeline_table_rule_delete(char **tokens,
3676         uint32_t n_tokens,
3677         char *out,
3678         size_t out_size)
3679 {
3680         struct table_rule_match m;
3681         char *pipeline_name;
3682         uint32_t table_id, n_tokens_parsed, t0;
3683         int status;
3684
3685         if (n_tokens < 8) {
3686                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3687                 return;
3688         }
3689
3690         pipeline_name = tokens[1];
3691
3692         if (strcmp(tokens[2], "table") != 0) {
3693                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3694                 return;
3695         }
3696
3697         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3698                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3699                 return;
3700         }
3701
3702         if (strcmp(tokens[4], "rule") != 0) {
3703                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3704                 return;
3705         }
3706
3707         if (strcmp(tokens[5], "delete") != 0) {
3708                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3709                 return;
3710         }
3711
3712         t0 = 6;
3713
3714         /* match */
3715         n_tokens_parsed = parse_match(tokens + t0,
3716                 n_tokens - t0,
3717                 out,
3718                 out_size,
3719                 &m);
3720         if (n_tokens_parsed == 0)
3721                 return;
3722         t0 += n_tokens_parsed;
3723
3724         if (n_tokens != t0) {
3725                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3726                 return;
3727         }
3728
3729         status = pipeline_table_rule_delete(pipeline_name,
3730                 table_id,
3731                 &m);
3732         if (status) {
3733                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3734                 return;
3735         }
3736 }
3737
3738 /**
3739  * pipeline <pipeline_name> table <table_id> rule delete
3740  *    match
3741  *       default
3742  */
3743 static void
3744 cmd_pipeline_table_rule_delete_default(char **tokens,
3745         uint32_t n_tokens,
3746         char *out,
3747         size_t out_size)
3748 {
3749         char *pipeline_name;
3750         uint32_t table_id;
3751         int status;
3752
3753         if (n_tokens != 8) {
3754                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3755                 return;
3756         }
3757
3758         pipeline_name = tokens[1];
3759
3760         if (strcmp(tokens[2], "table") != 0) {
3761                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3762                 return;
3763         }
3764
3765         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3766                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3767                 return;
3768         }
3769
3770         if (strcmp(tokens[4], "rule") != 0) {
3771                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3772                 return;
3773         }
3774
3775         if (strcmp(tokens[5], "delete") != 0) {
3776                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3777                 return;
3778         }
3779
3780         if (strcmp(tokens[6], "match") != 0) {
3781                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3782                 return;
3783         }
3784
3785         if (strcmp(tokens[7], "default") != 0) {
3786                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3787                 return;
3788         }
3789
3790         status = pipeline_table_rule_delete_default(pipeline_name,
3791                 table_id);
3792         if (status) {
3793                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3794                 return;
3795         }
3796 }
3797
3798 /**
3799  * pipeline <pipeline_name> table <table_id> rule read stats [clear]
3800  */
3801 static void
3802 cmd_pipeline_table_rule_stats_read(char **tokens,
3803         uint32_t n_tokens __rte_unused,
3804         char *out,
3805         size_t out_size)
3806 {
3807         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
3808 }
3809
3810 /**
3811  * thread <thread_id> pipeline <pipeline_name> enable
3812  */
3813 static void
3814 cmd_thread_pipeline_enable(char **tokens,
3815         uint32_t n_tokens,
3816         char *out,
3817         size_t out_size)
3818 {
3819         char *pipeline_name;
3820         uint32_t thread_id;
3821         int status;
3822
3823         if (n_tokens != 5) {
3824                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3825                 return;
3826         }
3827
3828         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
3829                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
3830                 return;
3831         }
3832
3833         if (strcmp(tokens[2], "pipeline") != 0) {
3834                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
3835                 return;
3836         }
3837
3838         pipeline_name = tokens[3];
3839
3840         if (strcmp(tokens[4], "enable") != 0) {
3841                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
3842                 return;
3843         }
3844
3845         status = thread_pipeline_enable(thread_id, pipeline_name);
3846         if (status) {
3847                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
3848                 return;
3849         }
3850 }
3851
3852 /**
3853  * thread <thread_id> pipeline <pipeline_name> disable
3854  */
3855 static void
3856 cmd_thread_pipeline_disable(char **tokens,
3857         uint32_t n_tokens,
3858         char *out,
3859         size_t out_size)
3860 {
3861         char *pipeline_name;
3862         uint32_t thread_id;
3863         int status;
3864
3865         if (n_tokens != 5) {
3866                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3867                 return;
3868         }
3869
3870         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
3871                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
3872                 return;
3873         }
3874
3875         if (strcmp(tokens[2], "pipeline") != 0) {
3876                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
3877                 return;
3878         }
3879
3880         pipeline_name = tokens[3];
3881
3882         if (strcmp(tokens[4], "disable") != 0) {
3883                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
3884                 return;
3885         }
3886
3887         status = thread_pipeline_disable(thread_id, pipeline_name);
3888         if (status) {
3889                 snprintf(out, out_size, MSG_CMD_FAIL,
3890                         "thread pipeline disable");
3891                 return;
3892         }
3893 }
3894
3895 void
3896 cli_process(char *in, char *out, size_t out_size)
3897 {
3898         char *tokens[CMD_MAX_TOKENS];
3899         uint32_t n_tokens = RTE_DIM(tokens);
3900         int status;
3901
3902         if (is_comment(in))
3903                 return;
3904
3905         status = parse_tokenize_string(in, tokens, &n_tokens);
3906         if (status) {
3907                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
3908                 return;
3909         }
3910
3911         if (n_tokens == 0)
3912                 return;
3913
3914         if (strcmp(tokens[0], "mempool") == 0) {
3915                 cmd_mempool(tokens, n_tokens, out, out_size);
3916                 return;
3917         }
3918
3919         if (strcmp(tokens[0], "link") == 0) {
3920                 cmd_link(tokens, n_tokens, out, out_size);
3921                 return;
3922         }
3923
3924         if (strcmp(tokens[0], "swq") == 0) {
3925                 cmd_swq(tokens, n_tokens, out, out_size);
3926                 return;
3927         }
3928
3929         if (strcmp(tokens[0], "tmgr") == 0) {
3930                 if ((n_tokens >= 3) &&
3931                         (strcmp(tokens[1], "subport") == 0) &&
3932                         (strcmp(tokens[2], "profile") == 0)) {
3933                         cmd_tmgr_subport_profile(tokens, n_tokens,
3934                                 out, out_size);
3935                         return;
3936                 }
3937
3938                 if ((n_tokens >= 3) &&
3939                         (strcmp(tokens[1], "pipe") == 0) &&
3940                         (strcmp(tokens[2], "profile") == 0)) {
3941                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
3942                         return;
3943                 }
3944
3945                 if ((n_tokens >= 5) &&
3946                         (strcmp(tokens[2], "subport") == 0) &&
3947                         (strcmp(tokens[4], "profile") == 0)) {
3948                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
3949                         return;
3950                 }
3951
3952                 if ((n_tokens >= 5) &&
3953                         (strcmp(tokens[2], "subport") == 0) &&
3954                         (strcmp(tokens[4], "pipe") == 0)) {
3955                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
3956                         return;
3957                 }
3958
3959                 cmd_tmgr(tokens, n_tokens, out, out_size);
3960                 return;
3961         }
3962
3963         if (strcmp(tokens[0], "tap") == 0) {
3964                 cmd_tap(tokens, n_tokens, out, out_size);
3965                 return;
3966         }
3967
3968         if (strcmp(tokens[0], "kni") == 0) {
3969                 cmd_kni(tokens, n_tokens, out, out_size);
3970                 return;
3971         }
3972
3973         if (strcmp(tokens[0], "port") == 0) {
3974                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
3975                 return;
3976         }
3977
3978         if (strcmp(tokens[0], "table") == 0) {
3979                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
3980                 return;
3981         }
3982
3983         if (strcmp(tokens[0], "pipeline") == 0) {
3984                 if ((n_tokens >= 3) &&
3985                         (strcmp(tokens[2], "period") == 0)) {
3986                         cmd_pipeline(tokens, n_tokens, out, out_size);
3987                         return;
3988                 }
3989
3990                 if ((n_tokens >= 5) &&
3991                         (strcmp(tokens[2], "port") == 0) &&
3992                         (strcmp(tokens[3], "in") == 0) &&
3993                         (strcmp(tokens[4], "bsz") == 0)) {
3994                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
3995                         return;
3996                 }
3997
3998                 if ((n_tokens >= 5) &&
3999                         (strcmp(tokens[2], "port") == 0) &&
4000                         (strcmp(tokens[3], "out") == 0) &&
4001                         (strcmp(tokens[4], "bsz") == 0)) {
4002                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
4003                         return;
4004                 }
4005
4006                 if ((n_tokens >= 4) &&
4007                         (strcmp(tokens[2], "table") == 0) &&
4008                         (strcmp(tokens[3], "match") == 0)) {
4009                         cmd_pipeline_table(tokens, n_tokens, out, out_size);
4010                         return;
4011                 }
4012
4013                 if ((n_tokens >= 6) &&
4014                         (strcmp(tokens[2], "port") == 0) &&
4015                         (strcmp(tokens[3], "in") == 0) &&
4016                         (strcmp(tokens[5], "table") == 0)) {
4017                         cmd_pipeline_port_in_table(tokens, n_tokens,
4018                                 out, out_size);
4019                         return;
4020                 }
4021
4022                 if ((n_tokens >= 6) &&
4023                         (strcmp(tokens[2], "port") == 0) &&
4024                         (strcmp(tokens[3], "in") == 0) &&
4025                         (strcmp(tokens[5], "stats") == 0)) {
4026                         cmd_pipeline_port_in_stats(tokens, n_tokens,
4027                                 out, out_size);
4028                         return;
4029                 }
4030
4031                 if ((n_tokens >= 6) &&
4032                         (strcmp(tokens[2], "port") == 0) &&
4033                         (strcmp(tokens[3], "in") == 0) &&
4034                         (strcmp(tokens[5], "enable") == 0)) {
4035                         cmd_pipeline_port_in_enable(tokens, n_tokens,
4036                                 out, out_size);
4037                         return;
4038                 }
4039
4040                 if ((n_tokens >= 6) &&
4041                         (strcmp(tokens[2], "port") == 0) &&
4042                         (strcmp(tokens[3], "in") == 0) &&
4043                         (strcmp(tokens[5], "disable") == 0)) {
4044                         cmd_pipeline_port_in_disable(tokens, n_tokens,
4045                                 out, out_size);
4046                         return;
4047                 }
4048
4049                 if ((n_tokens >= 6) &&
4050                         (strcmp(tokens[2], "port") == 0) &&
4051                         (strcmp(tokens[3], "out") == 0) &&
4052                         (strcmp(tokens[5], "stats") == 0)) {
4053                         cmd_pipeline_port_out_stats(tokens, n_tokens,
4054                                 out, out_size);
4055                         return;
4056                 }
4057
4058                 if ((n_tokens >= 5) &&
4059                         (strcmp(tokens[2], "table") == 0) &&
4060                         (strcmp(tokens[4], "stats") == 0)) {
4061                         cmd_pipeline_table_stats(tokens, n_tokens,
4062                                 out, out_size);
4063                         return;
4064                 }
4065
4066                 if ((n_tokens >= 7) &&
4067                         (strcmp(tokens[2], "table") == 0) &&
4068                         (strcmp(tokens[4], "rule") == 0) &&
4069                         (strcmp(tokens[5], "add") == 0) &&
4070                         (strcmp(tokens[6], "match") == 0)) {
4071                         if ((n_tokens >= 8) &&
4072                                 (strcmp(tokens[7], "default") == 0)) {
4073                                 cmd_pipeline_table_rule_add_default(tokens,
4074                                         n_tokens, out, out_size);
4075                                 return;
4076                         }
4077
4078                         cmd_pipeline_table_rule_add(tokens, n_tokens,
4079                                 out, out_size);
4080                         return;
4081                 }
4082
4083                 if ((n_tokens >= 7) &&
4084                         (strcmp(tokens[2], "table") == 0) &&
4085                         (strcmp(tokens[4], "rule") == 0) &&
4086                         (strcmp(tokens[5], "add") == 0) &&
4087                         (strcmp(tokens[6], "bulk") == 0)) {
4088                         cmd_pipeline_table_rule_add_bulk(tokens,
4089                                 n_tokens, out, out_size);
4090                         return;
4091                 }
4092
4093                 if ((n_tokens >= 7) &&
4094                         (strcmp(tokens[2], "table") == 0) &&
4095                         (strcmp(tokens[4], "rule") == 0) &&
4096                         (strcmp(tokens[5], "delete") == 0) &&
4097                         (strcmp(tokens[6], "match") == 0)) {
4098                         if ((n_tokens >= 8) &&
4099                                 (strcmp(tokens[7], "default") == 0)) {
4100                                 cmd_pipeline_table_rule_delete_default(tokens,
4101                                         n_tokens, out, out_size);
4102                                 return;
4103                                 }
4104
4105                         cmd_pipeline_table_rule_delete(tokens, n_tokens,
4106                                 out, out_size);
4107                         return;
4108                 }
4109
4110                 if ((n_tokens >= 7) &&
4111                         (strcmp(tokens[2], "table") == 0) &&
4112                         (strcmp(tokens[4], "rule") == 0) &&
4113                         (strcmp(tokens[5], "read") == 0) &&
4114                         (strcmp(tokens[6], "stats") == 0)) {
4115                         cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
4116                                 out, out_size);
4117                         return;
4118                 }
4119         }
4120
4121         if (strcmp(tokens[0], "thread") == 0) {
4122                 if ((n_tokens >= 5) &&
4123                         (strcmp(tokens[4], "enable") == 0)) {
4124                         cmd_thread_pipeline_enable(tokens, n_tokens,
4125                                 out, out_size);
4126                         return;
4127                 }
4128
4129                 if ((n_tokens >= 5) &&
4130                         (strcmp(tokens[4], "disable") == 0)) {
4131                         cmd_thread_pipeline_disable(tokens, n_tokens,
4132                                 out, out_size);
4133                         return;
4134                 }
4135         }
4136
4137         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
4138 }
4139
4140 int
4141 cli_script_process(const char *file_name,
4142         size_t msg_in_len_max,
4143         size_t msg_out_len_max)
4144 {
4145         char *msg_in = NULL, *msg_out = NULL;
4146         FILE *f = NULL;
4147
4148         /* Check input arguments */
4149         if ((file_name == NULL) ||
4150                 (strlen(file_name) == 0) ||
4151                 (msg_in_len_max == 0) ||
4152                 (msg_out_len_max == 0))
4153                 return -EINVAL;
4154
4155         msg_in = malloc(msg_in_len_max + 1);
4156         msg_out = malloc(msg_out_len_max + 1);
4157         if ((msg_in == NULL) ||
4158                 (msg_out == NULL)) {
4159                 free(msg_out);
4160                 free(msg_in);
4161                 return -ENOMEM;
4162         }
4163
4164         /* Open input file */
4165         f = fopen(file_name, "r");
4166         if (f == NULL) {
4167                 free(msg_out);
4168                 free(msg_in);
4169                 return -EIO;
4170         }
4171
4172         /* Read file */
4173         for ( ; ; ) {
4174                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
4175                         break;
4176
4177                 printf("%s", msg_in);
4178                 msg_out[0] = 0;
4179
4180                 cli_process(msg_in,
4181                         msg_out,
4182                         msg_out_len_max);
4183
4184                 if (strlen(msg_out))
4185                         printf("%s", msg_out);
4186         }
4187
4188         /* Close file */
4189         fclose(f);
4190         free(msg_out);
4191         free(msg_in);
4192         return 0;
4193 }
4194
4195 static int
4196 cli_rule_file_process(const char *file_name,
4197         size_t line_len_max,
4198         struct table_rule_match *m,
4199         struct table_rule_action *a,
4200         uint32_t *n_rules,
4201         uint32_t *line_number,
4202         char *out,
4203         size_t out_size)
4204 {
4205         FILE *f = NULL;
4206         char *line = NULL;
4207         uint32_t rule_id, line_id;
4208         int status = 0;
4209
4210         /* Check input arguments */
4211         if ((file_name == NULL) ||
4212                 (strlen(file_name) == 0) ||
4213                 (line_len_max == 0)) {
4214                 *line_number = 0;
4215                 return -EINVAL;
4216         }
4217
4218         /* Memory allocation */
4219         line = malloc(line_len_max + 1);
4220         if (line == NULL) {
4221                 *line_number = 0;
4222                 return -ENOMEM;
4223         }
4224
4225         /* Open file */
4226         f = fopen(file_name, "r");
4227         if (f == NULL) {
4228                 *line_number = 0;
4229                 free(line);
4230                 return -EIO;
4231         }
4232
4233         /* Read file */
4234         for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
4235                 char *tokens[CMD_MAX_TOKENS];
4236                 uint32_t n_tokens, n_tokens_parsed, t0;
4237
4238                 /* Read next line from file. */
4239                 if (fgets(line, line_len_max + 1, f) == NULL)
4240                         break;
4241
4242                 /* Comment. */
4243                 if (is_comment(line))
4244                         continue;
4245
4246                 /* Parse line. */
4247                 n_tokens = RTE_DIM(tokens);
4248                 status = parse_tokenize_string(line, tokens, &n_tokens);
4249                 if (status) {
4250                         status = -EINVAL;
4251                         break;
4252                 }
4253
4254                 /* Empty line. */
4255                 if (n_tokens == 0)
4256                         continue;
4257                 t0 = 0;
4258
4259                 /* Rule match. */
4260                 n_tokens_parsed = parse_match(tokens + t0,
4261                         n_tokens - t0,
4262                         out,
4263                         out_size,
4264                         &m[rule_id]);
4265                 if (n_tokens_parsed == 0) {
4266                         status = -EINVAL;
4267                         break;
4268                 }
4269                 t0 += n_tokens_parsed;
4270
4271                 /* Rule action. */
4272                 n_tokens_parsed = parse_table_action(tokens + t0,
4273                         n_tokens - t0,
4274                         out,
4275                         out_size,
4276                         &a[rule_id]);
4277                 if (n_tokens_parsed == 0) {
4278                         status = -EINVAL;
4279                         break;
4280                 }
4281                 t0 += n_tokens_parsed;
4282
4283                 /* Line completed. */
4284                 if (t0 < n_tokens) {
4285                         status = -EINVAL;
4286                         break;
4287                 }
4288
4289                 /* Increment rule count */
4290                 rule_id++;
4291         }
4292
4293         /* Close file */
4294         fclose(f);
4295
4296         /* Memory free */
4297         free(line);
4298
4299         *n_rules = rule_id;
4300         *line_number = line_id;
4301         return status;
4302 }