examples/ip_pipeline: fix leak on DSCP parsing
[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,
809                                 "port in action profile balance");
810                         return;
811                 }
812
813                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
814                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
815                         return;
816                 }
817
818                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
819                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
820                         return;
821                 }
822
823                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
824                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
825                         return;
826                 }
827
828                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
829                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
830                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
831                         return;
832                 }
833
834                 if (strcmp(tokens[t0 + 5], "port") != 0) {
835                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
836                         return;
837                 }
838
839                 for (i = 0; i < 16; i++)
840                         if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) {
841                                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
842                                 return;
843                         }
844
845                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
846                 t0 += 22;
847         } /* balance */
848
849         if (t0 < n_tokens) {
850                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
851                 return;
852         }
853
854         ap = port_in_action_profile_create(name, &p);
855         if (ap == NULL) {
856                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
857                 return;
858         }
859 }
860
861 /**
862  * table action profile <profile_name>
863  *  ipv4 | ipv6
864  *  offset <ip_offset>
865  *  fwd
866  *  [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]
867  *  [meter srtcm | trtcm
868  *      tc <n_tc>
869  *      stats none | pkts | bytes | both]
870  *  [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
871  *  [encap ether | vlan | qinq | mpls | pppoe]
872  *  [nat src | dst
873  *      proto udp | tcp]
874  *  [ttl drop | fwd
875  *      stats none | pkts]
876  *  [stats pkts | bytes | both]
877  *  [time]
878  */
879 static void
880 cmd_table_action_profile(char **tokens,
881         uint32_t n_tokens,
882         char *out,
883         size_t out_size)
884 {
885         struct table_action_profile_params p;
886         struct table_action_profile *ap;
887         char *name;
888         uint32_t t0;
889
890         memset(&p, 0, sizeof(p));
891
892         if (n_tokens < 8) {
893                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
894                 return;
895         }
896
897         if (strcmp(tokens[1], "action") != 0) {
898                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
899                 return;
900         }
901
902         if (strcmp(tokens[2], "profile") != 0) {
903                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
904                 return;
905         }
906
907         name = tokens[3];
908
909         if (strcmp(tokens[4], "ipv4") == 0)
910                 p.common.ip_version = 1;
911         else if (strcmp(tokens[4], "ipv6") == 0)
912                 p.common.ip_version = 0;
913         else {
914                 snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
915                 return;
916         }
917
918         if (strcmp(tokens[5], "offset") != 0) {
919                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
920                 return;
921         }
922
923         if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
924                 snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
925                 return;
926         }
927
928         if (strcmp(tokens[7], "fwd") != 0) {
929                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
930                 return;
931         }
932
933         p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
934
935         t0 = 8;
936         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
937                 if (n_tokens < t0 + 7) {
938                         snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
939                         return;
940                 }
941
942                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
943                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
944                         return;
945                 }
946
947                 if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
948                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
949                         return;
950                 }
951
952                 if (strcmp(tokens[t0 + 3], "mask") != 0) {
953                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
954                         return;
955                 }
956
957                 p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
958                 if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
959                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
960                         return;
961                 }
962
963                 if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
964                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
965                         return;
966                 }
967
968                 if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) {
969                         snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
970                         return;
971                 }
972
973                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
974                 t0 += 7;
975         } /* balance */
976
977         if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
978                 if (n_tokens < t0 + 6) {
979                         snprintf(out, out_size, MSG_ARG_MISMATCH,
980                                 "table action profile meter");
981                         return;
982                 }
983
984                 if (strcmp(tokens[t0 + 1], "srtcm") == 0)
985                         p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
986                 else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
987                         p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
988                 else {
989                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
990                                 "srtcm or trtcm");
991                         return;
992                 }
993
994                 if (strcmp(tokens[t0 + 2], "tc") != 0) {
995                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
996                         return;
997                 }
998
999                 if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
1000                         snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
1001                         return;
1002                 }
1003
1004                 if (strcmp(tokens[t0 + 4], "stats") != 0) {
1005                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1006                         return;
1007                 }
1008
1009                 if (strcmp(tokens[t0 + 5], "none") == 0) {
1010                         p.mtr.n_packets_enabled = 0;
1011                         p.mtr.n_bytes_enabled = 0;
1012                 } else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
1013                         p.mtr.n_packets_enabled = 1;
1014                         p.mtr.n_bytes_enabled = 0;
1015                 } else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
1016                         p.mtr.n_packets_enabled = 0;
1017                         p.mtr.n_bytes_enabled = 1;
1018                 } else if (strcmp(tokens[t0 + 5], "both") == 0) {
1019                         p.mtr.n_packets_enabled = 1;
1020                         p.mtr.n_bytes_enabled = 1;
1021                 } else {
1022                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1023                                 "none or pkts or bytes or both");
1024                         return;
1025                 }
1026
1027                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
1028                 t0 += 6;
1029         } /* meter */
1030
1031         if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
1032                 if (n_tokens < t0 + 5) {
1033                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1034                                 "table action profile tm");
1035                         return;
1036                 }
1037
1038                 if (strcmp(tokens[t0 + 1], "spp") != 0) {
1039                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
1040                         return;
1041                 }
1042
1043                 if (parser_read_uint32(&p.tm.n_subports_per_port,
1044                         tokens[t0 + 2]) != 0) {
1045                         snprintf(out, out_size, MSG_ARG_INVALID,
1046                                 "n_subports_per_port");
1047                         return;
1048                 }
1049
1050                 if (strcmp(tokens[t0 + 3], "pps") != 0) {
1051                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1052                         return;
1053                 }
1054
1055                 if (parser_read_uint32(&p.tm.n_pipes_per_subport,
1056                         tokens[t0 + 4]) != 0) {
1057                         snprintf(out, out_size, MSG_ARG_INVALID,
1058                                 "n_pipes_per_subport");
1059                         return;
1060                 }
1061
1062                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1063                 t0 += 5;
1064         } /* tm */
1065
1066         if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
1067                 if (n_tokens < t0 + 2) {
1068                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1069                                 "action profile encap");
1070                         return;
1071                 }
1072
1073                 if (strcmp(tokens[t0 + 1], "ether") == 0)
1074                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1075                 else if (strcmp(tokens[t0 + 1], "vlan") == 0)
1076                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1077                 else if (strcmp(tokens[t0 + 1], "qinq") == 0)
1078                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1079                 else if (strcmp(tokens[t0 + 1], "mpls") == 0)
1080                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1081                 else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
1082                         p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1083                 else {
1084                         snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1085                         return;
1086                 }
1087
1088                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1089                 t0 += 2;
1090         } /* encap */
1091
1092         if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
1093                 if (n_tokens < t0 + 4) {
1094                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1095                                 "table action profile nat");
1096                         return;
1097                 }
1098
1099                 if (strcmp(tokens[t0 + 1], "src") == 0)
1100                         p.nat.source_nat = 1;
1101                 else if (strcmp(tokens[t0 + 1], "dst") == 0)
1102                         p.nat.source_nat = 0;
1103                 else {
1104                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1105                                 "src or dst");
1106                         return;
1107                 }
1108
1109                 if (strcmp(tokens[t0 + 2], "proto") != 0) {
1110                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1111                         return;
1112                 }
1113
1114                 if (strcmp(tokens[t0 + 3], "tcp") == 0)
1115                         p.nat.proto = 0x06;
1116                 else if (strcmp(tokens[t0 + 3], "udp") == 0)
1117                         p.nat.proto = 0x11;
1118                 else {
1119                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1120                                 "tcp or udp");
1121                         return;
1122                 }
1123
1124                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1125                 t0 += 4;
1126         } /* nat */
1127
1128         if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
1129                 if (n_tokens < t0 + 4) {
1130                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1131                                 "table action profile ttl");
1132                         return;
1133                 }
1134
1135                 if (strcmp(tokens[t0 + 1], "drop") == 0)
1136                         p.ttl.drop = 1;
1137                 else if (strcmp(tokens[t0 + 1], "fwd") == 0)
1138                         p.ttl.drop = 0;
1139                 else {
1140                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1141                                 "drop or fwd");
1142                         return;
1143                 }
1144
1145                 if (strcmp(tokens[t0 + 2], "stats") != 0) {
1146                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1147                         return;
1148                 }
1149
1150                 if (strcmp(tokens[t0 + 3], "none") == 0)
1151                         p.ttl.n_packets_enabled = 0;
1152                 else if (strcmp(tokens[t0 + 3], "pkts") == 0)
1153                         p.ttl.n_packets_enabled = 1;
1154                 else {
1155                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1156                                 "none or pkts");
1157                         return;
1158                 }
1159
1160                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1161                 t0 += 4;
1162         } /* ttl */
1163
1164         if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
1165                 if (n_tokens < t0 + 2) {
1166                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1167                                 "table action profile stats");
1168                         return;
1169                 }
1170
1171                 if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1172                         p.stats.n_packets_enabled = 1;
1173                         p.stats.n_bytes_enabled = 0;
1174                 } else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1175                         p.stats.n_packets_enabled = 0;
1176                         p.stats.n_bytes_enabled = 1;
1177                 } else if (strcmp(tokens[t0 + 1], "both") == 0) {
1178                         p.stats.n_packets_enabled = 1;
1179                         p.stats.n_bytes_enabled = 1;
1180                 } else {
1181                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1182                                 "pkts or bytes or both");
1183                         return;
1184                 }
1185
1186                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1187                 t0 += 2;
1188         } /* stats */
1189
1190         if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
1191                 p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1192                 t0 += 1;
1193         } /* time */
1194
1195         if (t0 < n_tokens) {
1196                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1197                 return;
1198         }
1199
1200         ap = table_action_profile_create(name, &p);
1201         if (ap == NULL) {
1202                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1203                 return;
1204         }
1205 }
1206
1207 /**
1208  * pipeline <pipeline_name>
1209  *  period <timer_period_ms>
1210  *  offset_port_id <offset_port_id>
1211  *  cpu <cpu_id>
1212  */
1213 static void
1214 cmd_pipeline(char **tokens,
1215         uint32_t n_tokens,
1216         char *out,
1217         size_t out_size)
1218 {
1219         struct pipeline_params p;
1220         char *name;
1221         struct pipeline *pipeline;
1222
1223         if (n_tokens != 8) {
1224                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1225                 return;
1226         }
1227
1228         name = tokens[1];
1229
1230         if (strcmp(tokens[2], "period") != 0) {
1231                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
1232                 return;
1233         }
1234
1235         if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
1236                 snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
1237                 return;
1238         }
1239
1240         if (strcmp(tokens[4], "offset_port_id") != 0) {
1241                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
1242                 return;
1243         }
1244
1245         if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
1246                 snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
1247                 return;
1248         }
1249
1250         if (strcmp(tokens[6], "cpu") != 0) {
1251                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
1252                 return;
1253         }
1254
1255         if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
1256                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
1257                 return;
1258         }
1259
1260         pipeline = pipeline_create(name, &p);
1261         if (pipeline == NULL) {
1262                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1263                 return;
1264         }
1265 }
1266
1267 /**
1268  * pipeline <pipeline_name> port in
1269  *  bsz <burst_size>
1270  *  link <link_name> rxq <queue_id>
1271  *  | swq <swq_name>
1272  *  | tmgr <tmgr_name>
1273  *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
1274  *  | kni <kni_name>
1275  *  | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>
1276  *  [action <port_in_action_profile_name>]
1277  *  [disabled]
1278  */
1279 static void
1280 cmd_pipeline_port_in(char **tokens,
1281         uint32_t n_tokens,
1282         char *out,
1283         size_t out_size)
1284 {
1285         struct port_in_params p;
1286         char *pipeline_name;
1287         uint32_t t0;
1288         int enabled, status;
1289
1290         if (n_tokens < 7) {
1291                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1292                 return;
1293         }
1294
1295         pipeline_name = tokens[1];
1296
1297         if (strcmp(tokens[2], "port") != 0) {
1298                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1299                 return;
1300         }
1301
1302         if (strcmp(tokens[3], "in") != 0) {
1303                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1304                 return;
1305         }
1306
1307         if (strcmp(tokens[4], "bsz") != 0) {
1308                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1309                 return;
1310         }
1311
1312         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1313                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1314                 return;
1315         }
1316
1317         t0 = 6;
1318
1319         if (strcmp(tokens[t0], "link") == 0) {
1320                 if (n_tokens < t0 + 4) {
1321                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1322                                 "pipeline port in link");
1323                         return;
1324                 }
1325
1326                 p.type = PORT_IN_RXQ;
1327
1328                 p.dev_name = tokens[t0 + 1];
1329
1330                 if (strcmp(tokens[t0 + 2], "rxq") != 0) {
1331                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
1332                         return;
1333                 }
1334
1335                 if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1336                         snprintf(out, out_size, MSG_ARG_INVALID,
1337                                 "queue_id");
1338                         return;
1339                 }
1340                 t0 += 4;
1341         } else if (strcmp(tokens[t0], "swq") == 0) {
1342                 if (n_tokens < t0 + 2) {
1343                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1344                                 "pipeline port in swq");
1345                         return;
1346                 }
1347
1348                 p.type = PORT_IN_SWQ;
1349
1350                 p.dev_name = tokens[t0 + 1];
1351
1352                 t0 += 2;
1353         } else if (strcmp(tokens[t0], "tmgr") == 0) {
1354                 if (n_tokens < t0 + 2) {
1355                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1356                                 "pipeline port in tmgr");
1357                         return;
1358                 }
1359
1360                 p.type = PORT_IN_TMGR;
1361
1362                 p.dev_name = tokens[t0 + 1];
1363
1364                 t0 += 2;
1365         } else if (strcmp(tokens[t0], "tap") == 0) {
1366                 if (n_tokens < t0 + 6) {
1367                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1368                                 "pipeline port in tap");
1369                         return;
1370                 }
1371
1372                 p.type = PORT_IN_TAP;
1373
1374                 p.dev_name = tokens[t0 + 1];
1375
1376                 if (strcmp(tokens[t0 + 2], "mempool") != 0) {
1377                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1378                                 "mempool");
1379                         return;
1380                 }
1381
1382                 p.tap.mempool_name = tokens[t0 + 3];
1383
1384                 if (strcmp(tokens[t0 + 4], "mtu") != 0) {
1385                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1386                                 "mtu");
1387                         return;
1388                 }
1389
1390                 if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
1391                         snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
1392                         return;
1393                 }
1394
1395                 t0 += 6;
1396         } else if (strcmp(tokens[t0], "kni") == 0) {
1397                 if (n_tokens < t0 + 2) {
1398                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1399                                 "pipeline port in kni");
1400                         return;
1401                 }
1402
1403                 p.type = PORT_IN_KNI;
1404
1405                 p.dev_name = tokens[t0 + 1];
1406
1407                 t0 += 2;
1408         } else if (strcmp(tokens[t0], "source") == 0) {
1409                 if (n_tokens < t0 + 6) {
1410                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1411                                 "pipeline port in source");
1412                         return;
1413                 }
1414
1415                 p.type = PORT_IN_SOURCE;
1416
1417                 p.dev_name = NULL;
1418
1419                 if (strcmp(tokens[t0 + 1], "mempool") != 0) {
1420                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1421                                 "mempool");
1422                         return;
1423                 }
1424
1425                 p.source.mempool_name = tokens[t0 + 2];
1426
1427                 if (strcmp(tokens[t0 + 3], "file") != 0) {
1428                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1429                                 "file");
1430                         return;
1431                 }
1432
1433                 p.source.file_name = tokens[t0 + 4];
1434
1435                 if (strcmp(tokens[t0 + 5], "bpp") != 0) {
1436                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1437                                 "bpp");
1438                         return;
1439                 }
1440
1441                 if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) {
1442                         snprintf(out, out_size, MSG_ARG_INVALID,
1443                                 "n_bytes_per_pkt");
1444                         return;
1445                 }
1446
1447                 t0 += 7;
1448         } else {
1449                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1450                 return;
1451         }
1452
1453         p.action_profile_name = NULL;
1454         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1455                 if (n_tokens < t0 + 2) {
1456                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1457                         return;
1458                 }
1459
1460                 p.action_profile_name = tokens[t0 + 1];
1461
1462                 t0 += 2;
1463         }
1464
1465         enabled = 1;
1466         if ((n_tokens > t0) &&
1467                 (strcmp(tokens[t0], "disabled") == 0)) {
1468                 enabled = 0;
1469
1470                 t0 += 1;
1471         }
1472
1473         if (n_tokens != t0) {
1474                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1475                 return;
1476         }
1477
1478         status = pipeline_port_in_create(pipeline_name,
1479                 &p, enabled);
1480         if (status) {
1481                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1482                 return;
1483         }
1484 }
1485
1486 /**
1487  * pipeline <pipeline_name> port out
1488  *  bsz <burst_size>
1489  *  link <link_name> txq <txq_id>
1490  *  | swq <swq_name>
1491  *  | tmgr <tmgr_name>
1492  *  | tap <tap_name>
1493  *  | kni <kni_name>
1494  *  | sink [file <file_name> pkts <max_n_pkts>]
1495  */
1496 static void
1497 cmd_pipeline_port_out(char **tokens,
1498         uint32_t n_tokens,
1499         char *out,
1500         size_t out_size)
1501 {
1502         struct port_out_params p;
1503         char *pipeline_name;
1504         int status;
1505
1506         memset(&p, 0, sizeof(p));
1507
1508         if (n_tokens < 7) {
1509                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1510                 return;
1511         }
1512
1513         pipeline_name = tokens[1];
1514
1515         if (strcmp(tokens[2], "port") != 0) {
1516                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1517                 return;
1518         }
1519
1520         if (strcmp(tokens[3], "out") != 0) {
1521                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1522                 return;
1523         }
1524
1525         if (strcmp(tokens[4], "bsz") != 0) {
1526                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1527                 return;
1528         }
1529
1530         if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1531                 snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1532                 return;
1533         }
1534
1535         if (strcmp(tokens[6], "link") == 0) {
1536                 if (n_tokens != 10) {
1537                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1538                                 "pipeline port out link");
1539                         return;
1540                 }
1541
1542                 p.type = PORT_OUT_TXQ;
1543
1544                 p.dev_name = tokens[7];
1545
1546                 if (strcmp(tokens[8], "txq") != 0) {
1547                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1548                         return;
1549                 }
1550
1551                 if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
1552                         snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1553                         return;
1554                 }
1555         } else if (strcmp(tokens[6], "swq") == 0) {
1556                 if (n_tokens != 8) {
1557                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1558                                 "pipeline port out swq");
1559                         return;
1560                 }
1561
1562                 p.type = PORT_OUT_SWQ;
1563
1564                 p.dev_name = tokens[7];
1565         } else if (strcmp(tokens[6], "tmgr") == 0) {
1566                 if (n_tokens != 8) {
1567                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1568                                 "pipeline port out tmgr");
1569                         return;
1570                 }
1571
1572                 p.type = PORT_OUT_TMGR;
1573
1574                 p.dev_name = tokens[7];
1575         } else if (strcmp(tokens[6], "tap") == 0) {
1576                 if (n_tokens != 8) {
1577                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1578                                 "pipeline port out tap");
1579                         return;
1580                 }
1581
1582                 p.type = PORT_OUT_TAP;
1583
1584                 p.dev_name = tokens[7];
1585         } else if (strcmp(tokens[6], "kni") == 0) {
1586                 if (n_tokens != 8) {
1587                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1588                                 "pipeline port out kni");
1589                         return;
1590                 }
1591
1592                 p.type = PORT_OUT_KNI;
1593
1594                 p.dev_name = tokens[7];
1595         } else if (strcmp(tokens[6], "sink") == 0) {
1596                 if ((n_tokens != 7) && (n_tokens != 11)) {
1597                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1598                                 "pipeline port out sink");
1599                         return;
1600                 }
1601
1602                 p.type = PORT_OUT_SINK;
1603
1604                 p.dev_name = NULL;
1605
1606                 if (n_tokens == 7) {
1607                         p.sink.file_name = NULL;
1608                         p.sink.max_n_pkts = 0;
1609                 } else {
1610                         if (strcmp(tokens[7], "file") != 0) {
1611                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1612                                         "file");
1613                                 return;
1614                         }
1615
1616                         p.sink.file_name = tokens[8];
1617
1618                         if (strcmp(tokens[9], "pkts") != 0) {
1619                                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1620                                 return;
1621                         }
1622
1623                         if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) {
1624                                 snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1625                                 return;
1626                         }
1627                 }
1628         } else {
1629                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1630                 return;
1631         }
1632
1633         status = pipeline_port_out_create(pipeline_name, &p);
1634         if (status) {
1635                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1636                 return;
1637         }
1638 }
1639
1640 /**
1641  * pipeline <pipeline_name> table
1642  *      match
1643  *      acl
1644  *          ipv4 | ipv6
1645  *          offset <ip_header_offset>
1646  *          size <n_rules>
1647  *      | array
1648  *          offset <key_offset>
1649  *          size <n_keys>
1650  *      | hash
1651  *          ext | lru
1652  *          key <key_size>
1653  *          mask <key_mask>
1654  *          offset <key_offset>
1655  *          buckets <n_buckets>
1656  *          size <n_keys>
1657  *      | lpm
1658  *          ipv4 | ipv6
1659  *          offset <ip_header_offset>
1660  *          size <n_rules>
1661  *      | stub
1662  *  [action <table_action_profile_name>]
1663  */
1664 static void
1665 cmd_pipeline_table(char **tokens,
1666         uint32_t n_tokens,
1667         char *out,
1668         size_t out_size)
1669 {
1670         uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1671         struct table_params p;
1672         char *pipeline_name;
1673         uint32_t t0;
1674         int status;
1675
1676         if (n_tokens < 5) {
1677                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1678                 return;
1679         }
1680
1681         pipeline_name = tokens[1];
1682
1683         if (strcmp(tokens[2], "table") != 0) {
1684                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1685                 return;
1686         }
1687
1688         if (strcmp(tokens[3], "match") != 0) {
1689                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
1690                 return;
1691         }
1692
1693         t0 = 4;
1694         if (strcmp(tokens[t0], "acl") == 0) {
1695                 if (n_tokens < t0 + 6) {
1696                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1697                                 "pipeline table acl");
1698                         return;
1699                 }
1700
1701                 p.match_type = TABLE_ACL;
1702
1703                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
1704                         p.match.acl.ip_version = 1;
1705                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
1706                         p.match.acl.ip_version = 0;
1707                 else {
1708                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1709                                 "ipv4 or ipv6");
1710                         return;
1711                 }
1712
1713                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1714                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1715                         return;
1716                 }
1717
1718                 if (parser_read_uint32(&p.match.acl.ip_header_offset,
1719                         tokens[t0 + 3]) != 0) {
1720                         snprintf(out, out_size, MSG_ARG_INVALID,
1721                                 "ip_header_offset");
1722                         return;
1723                 }
1724
1725                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1726                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1727                         return;
1728                 }
1729
1730                 if (parser_read_uint32(&p.match.acl.n_rules,
1731                         tokens[t0 + 5]) != 0) {
1732                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1733                         return;
1734                 }
1735
1736                 t0 += 6;
1737         } else if (strcmp(tokens[t0], "array") == 0) {
1738                 if (n_tokens < t0 + 5) {
1739                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1740                                 "pipeline table array");
1741                         return;
1742                 }
1743
1744                 p.match_type = TABLE_ARRAY;
1745
1746                 if (strcmp(tokens[t0 + 1], "offset") != 0) {
1747                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1748                         return;
1749                 }
1750
1751                 if (parser_read_uint32(&p.match.array.key_offset,
1752                         tokens[t0 + 2]) != 0) {
1753                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1754                         return;
1755                 }
1756
1757                 if (strcmp(tokens[t0 + 3], "size") != 0) {
1758                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1759                         return;
1760                 }
1761
1762                 if (parser_read_uint32(&p.match.array.n_keys,
1763                         tokens[t0 + 4]) != 0) {
1764                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1765                         return;
1766                 }
1767
1768                 t0 += 5;
1769         } else if (strcmp(tokens[t0], "hash") == 0) {
1770                 uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
1771
1772                 if (n_tokens < t0 + 12) {
1773                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1774                                 "pipeline table hash");
1775                         return;
1776                 }
1777
1778                 p.match_type = TABLE_HASH;
1779
1780                 if (strcmp(tokens[t0 + 1], "ext") == 0)
1781                         p.match.hash.extendable_bucket = 1;
1782                 else if (strcmp(tokens[t0 + 1], "lru") == 0)
1783                         p.match.hash.extendable_bucket = 0;
1784                 else {
1785                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1786                                 "ext or lru");
1787                         return;
1788                 }
1789
1790                 if (strcmp(tokens[t0 + 2], "key") != 0) {
1791                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
1792                         return;
1793                 }
1794
1795                 if ((parser_read_uint32(&p.match.hash.key_size,
1796                         tokens[t0 + 3]) != 0) ||
1797                         (p.match.hash.key_size == 0) ||
1798                         (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
1799                         snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
1800                         return;
1801                 }
1802
1803                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
1804                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1805                         return;
1806                 }
1807
1808                 if ((parse_hex_string(tokens[t0 + 5],
1809                         key_mask, &key_mask_size) != 0) ||
1810                         (key_mask_size != p.match.hash.key_size)) {
1811                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1812                         return;
1813                 }
1814                 p.match.hash.key_mask = key_mask;
1815
1816                 if (strcmp(tokens[t0 + 6], "offset") != 0) {
1817                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1818                         return;
1819                 }
1820
1821                 if (parser_read_uint32(&p.match.hash.key_offset,
1822                         tokens[t0 + 7]) != 0) {
1823                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1824                         return;
1825                 }
1826
1827                 if (strcmp(tokens[t0 + 8], "buckets") != 0) {
1828                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
1829                         return;
1830                 }
1831
1832                 if (parser_read_uint32(&p.match.hash.n_buckets,
1833                         tokens[t0 + 9]) != 0) {
1834                         snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
1835                         return;
1836                 }
1837
1838                 if (strcmp(tokens[t0 + 10], "size") != 0) {
1839                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1840                         return;
1841                 }
1842
1843                 if (parser_read_uint32(&p.match.hash.n_keys,
1844                         tokens[t0 + 11]) != 0) {
1845                         snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1846                         return;
1847                 }
1848
1849                 t0 += 12;
1850         } else if (strcmp(tokens[t0], "lpm") == 0) {
1851                 if (n_tokens < t0 + 6) {
1852                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1853                                 "pipeline table lpm");
1854                         return;
1855                 }
1856
1857                 p.match_type = TABLE_LPM;
1858
1859                 if (strcmp(tokens[t0 + 1], "ipv4") == 0)
1860                         p.match.lpm.key_size = 4;
1861                 else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
1862                         p.match.lpm.key_size = 16;
1863                 else {
1864                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1865                                 "ipv4 or ipv6");
1866                         return;
1867                 }
1868
1869                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
1870                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1871                         return;
1872                 }
1873
1874                 if (parser_read_uint32(&p.match.lpm.key_offset,
1875                         tokens[t0 + 3]) != 0) {
1876                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1877                         return;
1878                 }
1879
1880                 if (strcmp(tokens[t0 + 4], "size") != 0) {
1881                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1882                         return;
1883                 }
1884
1885                 if (parser_read_uint32(&p.match.lpm.n_rules,
1886                         tokens[t0 + 5]) != 0) {
1887                         snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1888                         return;
1889                 }
1890
1891                 t0 += 6;
1892         } else if (strcmp(tokens[t0], "stub") == 0) {
1893                 if (n_tokens < t0 + 1) {
1894                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1895                                 "pipeline table stub");
1896                         return;
1897                 }
1898
1899                 p.match_type = TABLE_STUB;
1900
1901                 t0 += 1;
1902         } else {
1903                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1904                 return;
1905         }
1906
1907         p.action_profile_name = NULL;
1908         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1909                 if (n_tokens < t0 + 2) {
1910                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1911                         return;
1912                 }
1913
1914                 p.action_profile_name = tokens[t0 + 1];
1915
1916                 t0 += 2;
1917         }
1918
1919         if (n_tokens > t0) {
1920                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1921                 return;
1922         }
1923
1924         status = pipeline_table_create(pipeline_name, &p);
1925         if (status) {
1926                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1927                 return;
1928         }
1929 }
1930
1931 /**
1932  * pipeline <pipeline_name> port in <port_id> table <table_id>
1933  */
1934 static void
1935 cmd_pipeline_port_in_table(char **tokens,
1936         uint32_t n_tokens,
1937         char *out,
1938         size_t out_size)
1939 {
1940         char *pipeline_name;
1941         uint32_t port_id, table_id;
1942         int status;
1943
1944         if (n_tokens != 7) {
1945                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1946                 return;
1947         }
1948
1949         pipeline_name = tokens[1];
1950
1951         if (strcmp(tokens[2], "port") != 0) {
1952                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1953                 return;
1954         }
1955
1956         if (strcmp(tokens[3], "in") != 0) {
1957                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1958                 return;
1959         }
1960
1961         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
1962                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1963                 return;
1964         }
1965
1966         if (strcmp(tokens[5], "table") != 0) {
1967                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1968                 return;
1969         }
1970
1971         if (parser_read_uint32(&table_id, tokens[6]) != 0) {
1972                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
1973                 return;
1974         }
1975
1976         status = pipeline_port_in_connect_to_table(pipeline_name,
1977                 port_id,
1978                 table_id);
1979         if (status) {
1980                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1981                 return;
1982         }
1983 }
1984
1985 /**
1986  * pipeline <pipeline_name> port in <port_id> stats read [clear]
1987  */
1988
1989 #define MSG_PIPELINE_PORT_IN_STATS                         \
1990         "Pkts in: %" PRIu64 "\n"                           \
1991         "Pkts dropped by AH: %" PRIu64 "\n"                \
1992         "Pkts dropped by other: %" PRIu64 "\n"
1993
1994 static void
1995 cmd_pipeline_port_in_stats(char **tokens,
1996         uint32_t n_tokens,
1997         char *out,
1998         size_t out_size)
1999 {
2000         struct rte_pipeline_port_in_stats stats;
2001         char *pipeline_name;
2002         uint32_t port_id;
2003         int clear, status;
2004
2005         if ((n_tokens != 7) && (n_tokens != 8)) {
2006                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2007                 return;
2008         }
2009
2010         pipeline_name = tokens[1];
2011
2012         if (strcmp(tokens[2], "port") != 0) {
2013                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2014                 return;
2015         }
2016
2017         if (strcmp(tokens[3], "in") != 0) {
2018                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2019                 return;
2020         }
2021
2022         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2023                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2024                 return;
2025         }
2026
2027         if (strcmp(tokens[5], "stats") != 0) {
2028                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2029                 return;
2030         }
2031
2032         if (strcmp(tokens[6], "read") != 0) {
2033                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2034                 return;
2035         }
2036
2037         clear = 0;
2038         if (n_tokens == 8) {
2039                 if (strcmp(tokens[7], "clear") != 0) {
2040                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2041                         return;
2042                 }
2043
2044                 clear = 1;
2045         }
2046
2047         status = pipeline_port_in_stats_read(pipeline_name,
2048                 port_id,
2049                 &stats,
2050                 clear);
2051         if (status) {
2052                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2053                 return;
2054         }
2055
2056         snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
2057                 stats.stats.n_pkts_in,
2058                 stats.n_pkts_dropped_by_ah,
2059                 stats.stats.n_pkts_drop);
2060 }
2061
2062 /**
2063  * pipeline <pipeline_name> port in <port_id> enable
2064  */
2065 static void
2066 cmd_pipeline_port_in_enable(char **tokens,
2067         uint32_t n_tokens,
2068         char *out,
2069         size_t out_size)
2070 {
2071         char *pipeline_name;
2072         uint32_t port_id;
2073         int status;
2074
2075         if (n_tokens != 6) {
2076                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2077                 return;
2078         }
2079
2080         pipeline_name = tokens[1];
2081
2082         if (strcmp(tokens[2], "port") != 0) {
2083                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2084                 return;
2085         }
2086
2087         if (strcmp(tokens[3], "in") != 0) {
2088                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2089                 return;
2090         }
2091
2092         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2093                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2094                 return;
2095         }
2096
2097         if (strcmp(tokens[5], "enable") != 0) {
2098                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2099                 return;
2100         }
2101
2102         status = pipeline_port_in_enable(pipeline_name, port_id);
2103         if (status) {
2104                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2105                 return;
2106         }
2107 }
2108
2109 /**
2110  * pipeline <pipeline_name> port in <port_id> disable
2111  */
2112 static void
2113 cmd_pipeline_port_in_disable(char **tokens,
2114         uint32_t n_tokens,
2115         char *out,
2116         size_t out_size)
2117 {
2118         char *pipeline_name;
2119         uint32_t port_id;
2120         int status;
2121
2122         if (n_tokens != 6) {
2123                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2124                 return;
2125         }
2126
2127         pipeline_name = tokens[1];
2128
2129         if (strcmp(tokens[2], "port") != 0) {
2130                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2131                 return;
2132         }
2133
2134         if (strcmp(tokens[3], "in") != 0) {
2135                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2136                 return;
2137         }
2138
2139         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2140                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2141                 return;
2142         }
2143
2144         if (strcmp(tokens[5], "disable") != 0) {
2145                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2146                 return;
2147         }
2148
2149         status = pipeline_port_in_disable(pipeline_name, port_id);
2150         if (status) {
2151                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2152                 return;
2153         }
2154 }
2155
2156 /**
2157  * pipeline <pipeline_name> port out <port_id> stats read [clear]
2158  */
2159 #define MSG_PIPELINE_PORT_OUT_STATS                        \
2160         "Pkts in: %" PRIu64 "\n"                           \
2161         "Pkts dropped by AH: %" PRIu64 "\n"                \
2162         "Pkts dropped by other: %" PRIu64 "\n"
2163
2164 static void
2165 cmd_pipeline_port_out_stats(char **tokens,
2166         uint32_t n_tokens,
2167         char *out,
2168         size_t out_size)
2169 {
2170         struct rte_pipeline_port_out_stats stats;
2171         char *pipeline_name;
2172         uint32_t port_id;
2173         int clear, status;
2174
2175         if ((n_tokens != 7) && (n_tokens != 8)) {
2176                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2177                 return;
2178         }
2179
2180         pipeline_name = tokens[1];
2181
2182         if (strcmp(tokens[2], "port") != 0) {
2183                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2184                 return;
2185         }
2186
2187         if (strcmp(tokens[3], "out") != 0) {
2188                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2189                 return;
2190         }
2191
2192         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2193                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2194                 return;
2195         }
2196
2197         if (strcmp(tokens[5], "stats") != 0) {
2198                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2199                 return;
2200         }
2201
2202         if (strcmp(tokens[6], "read") != 0) {
2203                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2204                 return;
2205         }
2206
2207         clear = 0;
2208         if (n_tokens == 8) {
2209                 if (strcmp(tokens[7], "clear") != 0) {
2210                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2211                         return;
2212                 }
2213
2214                 clear = 1;
2215         }
2216
2217         status = pipeline_port_out_stats_read(pipeline_name,
2218                 port_id,
2219                 &stats,
2220                 clear);
2221         if (status) {
2222                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2223                 return;
2224         }
2225
2226         snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
2227                 stats.stats.n_pkts_in,
2228                 stats.n_pkts_dropped_by_ah,
2229                 stats.stats.n_pkts_drop);
2230 }
2231
2232 /**
2233  * pipeline <pipeline_name> table <table_id> stats read [clear]
2234  */
2235 #define MSG_PIPELINE_TABLE_STATS                                     \
2236         "Pkts in: %" PRIu64 "\n"                                     \
2237         "Pkts in with lookup miss: %" PRIu64 "\n"                    \
2238         "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
2239         "Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
2240         "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
2241         "Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
2242
2243 static void
2244 cmd_pipeline_table_stats(char **tokens,
2245         uint32_t n_tokens,
2246         char *out,
2247         size_t out_size)
2248 {
2249         struct rte_pipeline_table_stats stats;
2250         char *pipeline_name;
2251         uint32_t table_id;
2252         int clear, status;
2253
2254         if ((n_tokens != 6) && (n_tokens != 7)) {
2255                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2256                 return;
2257         }
2258
2259         pipeline_name = tokens[1];
2260
2261         if (strcmp(tokens[2], "table") != 0) {
2262                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2263                 return;
2264         }
2265
2266         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
2267                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2268                 return;
2269         }
2270
2271         if (strcmp(tokens[4], "stats") != 0) {
2272                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2273                 return;
2274         }
2275
2276         if (strcmp(tokens[5], "read") != 0) {
2277                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2278                 return;
2279         }
2280
2281         clear = 0;
2282         if (n_tokens == 7) {
2283                 if (strcmp(tokens[6], "clear") != 0) {
2284                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2285                         return;
2286                 }
2287
2288                 clear = 1;
2289         }
2290
2291         status = pipeline_table_stats_read(pipeline_name,
2292                 table_id,
2293                 &stats,
2294                 clear);
2295         if (status) {
2296                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2297                 return;
2298         }
2299
2300         snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
2301                 stats.stats.n_pkts_in,
2302                 stats.stats.n_pkts_lookup_miss,
2303                 stats.n_pkts_dropped_by_lkp_hit_ah,
2304                 stats.n_pkts_dropped_lkp_hit,
2305                 stats.n_pkts_dropped_by_lkp_miss_ah,
2306                 stats.n_pkts_dropped_lkp_miss);
2307 }
2308
2309 /**
2310  * <match> ::=
2311  *
2312  * match
2313  *    acl
2314  *       priority <priority>
2315  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
2316  *       <sp0> <sp1> <dp0> <dp1> <proto>
2317  *    | array <pos>
2318  *    | hash
2319  *       raw <key>
2320  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2321  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2322  *       | ipv4_addr <addr>
2323  *       | ipv6_addr <addr>
2324  *       | qinq <svlan> <cvlan>
2325  *    | lpm
2326  *       ipv4 | ipv6 <addr> <depth>
2327  */
2328 struct pkt_key_qinq {
2329         uint16_t ethertype_svlan;
2330         uint16_t svlan;
2331         uint16_t ethertype_cvlan;
2332         uint16_t cvlan;
2333 } __attribute__((__packed__));
2334
2335 struct pkt_key_ipv4_5tuple {
2336         uint8_t time_to_live;
2337         uint8_t proto;
2338         uint16_t hdr_checksum;
2339         uint32_t sa;
2340         uint32_t da;
2341         uint16_t sp;
2342         uint16_t dp;
2343 } __attribute__((__packed__));
2344
2345 struct pkt_key_ipv6_5tuple {
2346         uint16_t payload_length;
2347         uint8_t proto;
2348         uint8_t hop_limit;
2349         uint8_t sa[16];
2350         uint8_t da[16];
2351         uint16_t sp;
2352         uint16_t dp;
2353 } __attribute__((__packed__));
2354
2355 struct pkt_key_ipv4_addr {
2356         uint32_t addr;
2357 } __attribute__((__packed__));
2358
2359 struct pkt_key_ipv6_addr {
2360         uint8_t addr[16];
2361 } __attribute__((__packed__));
2362
2363 static uint32_t
2364 parse_match(char **tokens,
2365         uint32_t n_tokens,
2366         char *out,
2367         size_t out_size,
2368         struct table_rule_match *m)
2369 {
2370         memset(m, 0, sizeof(*m));
2371
2372         if (n_tokens < 2)
2373                 return 0;
2374
2375         if (strcmp(tokens[0], "match") != 0) {
2376                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2377                 return 0;
2378         }
2379
2380         if (strcmp(tokens[1], "acl") == 0) {
2381                 if (n_tokens < 14) {
2382                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2383                         return 0;
2384                 }
2385
2386                 m->match_type = TABLE_ACL;
2387
2388                 if (strcmp(tokens[2], "priority") != 0) {
2389                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
2390                         return 0;
2391                 }
2392
2393                 if (parser_read_uint32(&m->match.acl.priority,
2394                         tokens[3]) != 0) {
2395                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
2396                         return 0;
2397                 }
2398
2399                 if (strcmp(tokens[4], "ipv4") == 0) {
2400                         struct in_addr saddr, daddr;
2401
2402                         m->match.acl.ip_version = 1;
2403
2404                         if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
2405                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2406                                 return 0;
2407                         }
2408                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
2409
2410                         if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
2411                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2412                                 return 0;
2413                         }
2414                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
2415                 } else if (strcmp(tokens[4], "ipv6") == 0) {
2416                         struct in6_addr saddr, daddr;
2417
2418                         m->match.acl.ip_version = 0;
2419
2420                         if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
2421                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2422                                 return 0;
2423                         }
2424                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2425
2426                         if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2427                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2428                                 return 0;
2429                         }
2430                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
2431                 } else {
2432                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2433                                 "ipv4 or ipv6");
2434                         return 0;
2435                 }
2436
2437                 if (parser_read_uint32(&m->match.acl.sa_depth,
2438                         tokens[6]) != 0) {
2439                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
2440                         return 0;
2441                 }
2442
2443                 if (parser_read_uint32(&m->match.acl.da_depth,
2444                         tokens[8]) != 0) {
2445                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
2446                         return 0;
2447                 }
2448
2449                 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
2450                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
2451                         return 0;
2452                 }
2453
2454                 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
2455                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
2456                         return 0;
2457                 }
2458
2459                 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
2460                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
2461                         return 0;
2462                 }
2463
2464                 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
2465                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
2466                         return 0;
2467                 }
2468
2469                 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
2470                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
2471                         return 0;
2472                 }
2473
2474                 m->match.acl.proto_mask = 0xff;
2475
2476                 return 14;
2477         } /* acl */
2478
2479         if (strcmp(tokens[1], "array") == 0) {
2480                 if (n_tokens < 3) {
2481                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2482                         return 0;
2483                 }
2484
2485                 m->match_type = TABLE_ARRAY;
2486
2487                 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
2488                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
2489                         return 0;
2490                 }
2491
2492                 return 3;
2493         } /* array */
2494
2495         if (strcmp(tokens[1], "hash") == 0) {
2496                 if (n_tokens < 3) {
2497                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2498                         return 0;
2499                 }
2500
2501                 m->match_type = TABLE_HASH;
2502
2503                 if (strcmp(tokens[2], "raw") == 0) {
2504                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
2505
2506                         if (n_tokens < 4) {
2507                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2508                                         tokens[0]);
2509                                 return 0;
2510                         }
2511
2512                         if (parse_hex_string(tokens[3],
2513                                 m->match.hash.key, &key_size) != 0) {
2514                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
2515                                 return 0;
2516                         }
2517
2518                         return 4;
2519                 } /* hash raw */
2520
2521                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
2522                         struct pkt_key_ipv4_5tuple *ipv4 =
2523                                 (struct pkt_key_ipv4_5tuple *) m->match.hash.key;
2524                         struct in_addr saddr, daddr;
2525                         uint16_t sp, dp;
2526                         uint8_t proto;
2527
2528                         if (n_tokens < 8) {
2529                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2530                                         tokens[0]);
2531                                 return 0;
2532                         }
2533
2534                         if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
2535                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2536                                 return 0;
2537                         }
2538
2539                         if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
2540                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2541                                 return 0;
2542                         }
2543
2544                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2545                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2546                                 return 0;
2547                         }
2548
2549                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2550                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2551                                 return 0;
2552                         }
2553
2554                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2555                                 snprintf(out, out_size, MSG_ARG_INVALID,
2556                                         "proto");
2557                                 return 0;
2558                         }
2559
2560                         ipv4->sa = saddr.s_addr;
2561                         ipv4->da = daddr.s_addr;
2562                         ipv4->sp = rte_cpu_to_be_16(sp);
2563                         ipv4->dp = rte_cpu_to_be_16(dp);
2564                         ipv4->proto = proto;
2565
2566                         return 8;
2567                 } /* hash ipv4_5tuple */
2568
2569                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
2570                         struct pkt_key_ipv6_5tuple *ipv6 =
2571                                 (struct pkt_key_ipv6_5tuple *) m->match.hash.key;
2572                         struct in6_addr saddr, daddr;
2573                         uint16_t sp, dp;
2574                         uint8_t proto;
2575
2576                         if (n_tokens < 8) {
2577                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2578                                         tokens[0]);
2579                                 return 0;
2580                         }
2581
2582                         if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
2583                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2584                                 return 0;
2585                         }
2586
2587                         if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
2588                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2589                                 return 0;
2590                         }
2591
2592                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2593                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2594                                 return 0;
2595                         }
2596
2597                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2598                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2599                                 return 0;
2600                         }
2601
2602                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2603                                 snprintf(out, out_size, MSG_ARG_INVALID,
2604                                         "proto");
2605                                 return 0;
2606                         }
2607
2608                         memcpy(ipv6->sa, saddr.s6_addr, 16);
2609                         memcpy(ipv6->da, daddr.s6_addr, 16);
2610                         ipv6->sp = rte_cpu_to_be_16(sp);
2611                         ipv6->dp = rte_cpu_to_be_16(dp);
2612                         ipv6->proto = proto;
2613
2614                         return 8;
2615                 } /* hash ipv6_5tuple */
2616
2617                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
2618                         struct pkt_key_ipv4_addr *ipv4_addr =
2619                                 (struct pkt_key_ipv4_addr *) m->match.hash.key;
2620                         struct in_addr addr;
2621
2622                         if (n_tokens < 4) {
2623                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2624                                         tokens[0]);
2625                                 return 0;
2626                         }
2627
2628                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2629                                 snprintf(out, out_size, MSG_ARG_INVALID,
2630                                         "addr");
2631                                 return 0;
2632                         }
2633
2634                         ipv4_addr->addr = addr.s_addr;
2635
2636                         return 4;
2637                 } /* hash ipv4_addr */
2638
2639                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
2640                         struct pkt_key_ipv6_addr *ipv6_addr =
2641                                 (struct pkt_key_ipv6_addr *) m->match.hash.key;
2642                         struct in6_addr addr;
2643
2644                         if (n_tokens < 4) {
2645                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2646                                         tokens[0]);
2647                                 return 0;
2648                         }
2649
2650                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2651                                 snprintf(out, out_size, MSG_ARG_INVALID,
2652                                         "addr");
2653                                 return 0;
2654                         }
2655
2656                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
2657
2658                         return 4;
2659                 } /* hash ipv6_5tuple */
2660
2661                 if (strcmp(tokens[2], "qinq") == 0) {
2662                         struct pkt_key_qinq *qinq =
2663                                 (struct pkt_key_qinq *) m->match.hash.key;
2664                         uint16_t svlan, cvlan;
2665
2666                         if (n_tokens < 5) {
2667                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2668                                         tokens[0]);
2669                                 return 0;
2670                         }
2671
2672                         if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
2673                                 (svlan > 0xFFF)) {
2674                                 snprintf(out, out_size, MSG_ARG_INVALID,
2675                                         "svlan");
2676                                 return 0;
2677                         }
2678
2679                         if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
2680                                 (cvlan > 0xFFF)) {
2681                                 snprintf(out, out_size, MSG_ARG_INVALID,
2682                                         "cvlan");
2683                                 return 0;
2684                         }
2685
2686                         qinq->svlan = rte_cpu_to_be_16(svlan);
2687                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
2688
2689                         return 5;
2690                 } /* hash qinq */
2691
2692                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2693                 return 0;
2694         } /* hash */
2695
2696         if (strcmp(tokens[1], "lpm") == 0) {
2697                 if (n_tokens < 5) {
2698                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2699                         return 0;
2700                 }
2701
2702                 m->match_type = TABLE_LPM;
2703
2704                 if (strcmp(tokens[2], "ipv4") == 0) {
2705                         struct in_addr addr;
2706
2707                         m->match.lpm.ip_version = 1;
2708
2709                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2710                                 snprintf(out, out_size, MSG_ARG_INVALID,
2711                                         "addr");
2712                                 return 0;
2713                         }
2714
2715                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
2716                 } else if (strcmp(tokens[2], "ipv6") == 0) {
2717                         struct in6_addr addr;
2718
2719                         m->match.lpm.ip_version = 0;
2720
2721                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2722                                 snprintf(out, out_size, MSG_ARG_INVALID,
2723                                         "addr");
2724                                 return 0;
2725                         }
2726
2727                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
2728                 } else {
2729                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2730                                 "ipv4 or ipv6");
2731                         return 0;
2732                 }
2733
2734                 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
2735                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
2736                         return 0;
2737                 }
2738
2739                 return 5;
2740         } /* lpm */
2741
2742         snprintf(out, out_size, MSG_ARG_MISMATCH,
2743                 "acl or array or hash or lpm");
2744         return 0;
2745 }
2746
2747 /**
2748  * table_action ::=
2749  *
2750  * action
2751  *    fwd
2752  *       drop
2753  *       | port <port_id>
2754  *       | meta
2755  *       | table <table_id>
2756  *    [balance <out0> ... <out7>]
2757  *    [meter
2758  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2759  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2760  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2761  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
2762  *    [tm subport <subport_id> pipe <pipe_id>]
2763  *    [encap
2764  *       ether <da> <sa>
2765  *       | vlan <da> <sa> <pcp> <dei> <vid>
2766  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
2767  *       | mpls unicast | multicast
2768  *          <da> <sa>
2769  *          label0 <label> <tc> <ttl>
2770  *          [label1 <label> <tc> <ttl>
2771  *          [label2 <label> <tc> <ttl>
2772  *          [label3 <label> <tc> <ttl>]]]
2773  *       | pppoe <da> <sa> <session_id>]
2774  *    [nat ipv4 | ipv6 <addr> <port>]
2775  *    [ttl dec | keep]
2776  *    [stats]
2777  *    [time]
2778  *
2779  * where:
2780  *    <pa> ::= g | y | r | drop
2781  */
2782 static uint32_t
2783 parse_table_action_fwd(char **tokens,
2784         uint32_t n_tokens,
2785         struct table_rule_action *a)
2786 {
2787         if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
2788                 return 0;
2789
2790         tokens++;
2791         n_tokens--;
2792
2793         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
2794                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
2795                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2796                 return 1 + 1;
2797         }
2798
2799         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
2800                 uint32_t id;
2801
2802                 if ((n_tokens < 2) ||
2803                         parser_read_uint32(&id, tokens[1]))
2804                         return 0;
2805
2806                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
2807                 a->fwd.id = id;
2808                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2809                 return 1 + 2;
2810         }
2811
2812         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
2813                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
2814                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2815                 return 1 + 1;
2816         }
2817
2818         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
2819                 uint32_t id;
2820
2821                 if ((n_tokens < 2) ||
2822                         parser_read_uint32(&id, tokens[1]))
2823                         return 0;
2824
2825                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
2826                 a->fwd.id = id;
2827                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2828                 return 1 + 2;
2829         }
2830
2831         return 0;
2832 }
2833
2834 static uint32_t
2835 parse_table_action_balance(char **tokens,
2836         uint32_t n_tokens,
2837         struct table_rule_action *a)
2838 {
2839         uint32_t i;
2840
2841         if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0))
2842                 return 0;
2843
2844         tokens++;
2845         n_tokens--;
2846
2847         if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE)
2848                 return 0;
2849
2850         for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++)
2851                 if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
2852                         return 0;
2853
2854         a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
2855         return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE;
2856
2857 }
2858
2859 static int
2860 parse_policer_action(char *token, enum rte_table_action_policer *a)
2861 {
2862         if (strcmp(token, "g") == 0) {
2863                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
2864                 return 0;
2865         }
2866
2867         if (strcmp(token, "y") == 0) {
2868                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
2869                 return 0;
2870         }
2871
2872         if (strcmp(token, "r") == 0) {
2873                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
2874                 return 0;
2875         }
2876
2877         if (strcmp(token, "drop") == 0) {
2878                 *a = RTE_TABLE_ACTION_POLICER_DROP;
2879                 return 0;
2880         }
2881
2882         return -1;
2883 }
2884
2885 static uint32_t
2886 parse_table_action_meter_tc(char **tokens,
2887         uint32_t n_tokens,
2888         struct rte_table_action_mtr_tc_params *mtr)
2889 {
2890         if ((n_tokens < 9) ||
2891                 strcmp(tokens[0], "meter") ||
2892                 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
2893                 strcmp(tokens[2], "policer") ||
2894                 strcmp(tokens[3], "g") ||
2895                 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
2896                 strcmp(tokens[5], "y") ||
2897                 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
2898                 strcmp(tokens[7], "r") ||
2899                 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
2900                 return 0;
2901
2902         return 9;
2903 }
2904
2905 static uint32_t
2906 parse_table_action_meter(char **tokens,
2907         uint32_t n_tokens,
2908         struct table_rule_action *a)
2909 {
2910         if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
2911                 return 0;
2912
2913         tokens++;
2914         n_tokens--;
2915
2916         if ((n_tokens < 10) ||
2917                 strcmp(tokens[0], "tc0") ||
2918                 (parse_table_action_meter_tc(tokens + 1,
2919                         n_tokens - 1,
2920                         &a->mtr.mtr[0]) == 0))
2921                 return 0;
2922
2923         tokens += 10;
2924         n_tokens -= 10;
2925
2926         if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
2927                 a->mtr.tc_mask = 1;
2928                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2929                 return 1 + 10;
2930         }
2931
2932         if ((n_tokens < 30) ||
2933                 (parse_table_action_meter_tc(tokens + 1,
2934                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
2935                 strcmp(tokens[10], "tc2") ||
2936                 (parse_table_action_meter_tc(tokens + 11,
2937                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
2938                 strcmp(tokens[20], "tc3") ||
2939                 (parse_table_action_meter_tc(tokens + 21,
2940                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
2941                 return 0;
2942
2943         a->mtr.tc_mask = 0xF;
2944         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2945         return 1 + 10 + 3 * 10;
2946 }
2947
2948 static uint32_t
2949 parse_table_action_tm(char **tokens,
2950         uint32_t n_tokens,
2951         struct table_rule_action *a)
2952 {
2953         uint32_t subport_id, pipe_id;
2954
2955         if ((n_tokens < 5) ||
2956                 strcmp(tokens[0], "tm") ||
2957                 strcmp(tokens[1], "subport") ||
2958                 parser_read_uint32(&subport_id, tokens[2]) ||
2959                 strcmp(tokens[3], "pipe") ||
2960                 parser_read_uint32(&pipe_id, tokens[4]))
2961                 return 0;
2962
2963         a->tm.subport_id = subport_id;
2964         a->tm.pipe_id = pipe_id;
2965         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
2966         return 5;
2967 }
2968
2969 static uint32_t
2970 parse_table_action_encap(char **tokens,
2971         uint32_t n_tokens,
2972         struct table_rule_action *a)
2973 {
2974         if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
2975                 return 0;
2976
2977         tokens++;
2978         n_tokens--;
2979
2980         /* ether */
2981         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
2982                 if ((n_tokens < 3) ||
2983                         parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
2984                         parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
2985                         return 0;
2986
2987                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
2988                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2989                 return 1 + 3;
2990         }
2991
2992         /* vlan */
2993         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
2994                 uint32_t pcp, dei, vid;
2995
2996                 if ((n_tokens < 6) ||
2997                         parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
2998                         parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
2999                         parser_read_uint32(&pcp, tokens[3]) ||
3000                         (pcp > 0x7) ||
3001                         parser_read_uint32(&dei, tokens[4]) ||
3002                         (dei > 0x1) ||
3003                         parser_read_uint32(&vid, tokens[5]) ||
3004                         (vid > 0xFFF))
3005                         return 0;
3006
3007                 a->encap.vlan.vlan.pcp = pcp & 0x7;
3008                 a->encap.vlan.vlan.dei = dei & 0x1;
3009                 a->encap.vlan.vlan.vid = vid & 0xFFF;
3010                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
3011                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3012                 return 1 + 6;
3013         }
3014
3015         /* qinq */
3016         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
3017                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
3018                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3019
3020                 if ((n_tokens < 9) ||
3021                         parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
3022                         parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
3023                         parser_read_uint32(&svlan_pcp, tokens[3]) ||
3024                         (svlan_pcp > 0x7) ||
3025                         parser_read_uint32(&svlan_dei, tokens[4]) ||
3026                         (svlan_dei > 0x1) ||
3027                         parser_read_uint32(&svlan_vid, tokens[5]) ||
3028                         (svlan_vid > 0xFFF) ||
3029                         parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3030                         (cvlan_pcp > 0x7) ||
3031                         parser_read_uint32(&cvlan_dei, tokens[7]) ||
3032                         (cvlan_dei > 0x1) ||
3033                         parser_read_uint32(&cvlan_vid, tokens[8]) ||
3034                         (cvlan_vid > 0xFFF))
3035                         return 0;
3036
3037                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
3038                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
3039                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
3040                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
3041                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
3042                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
3043                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
3044                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3045                 return 1 + 9;
3046         }
3047
3048         /* mpls */
3049         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
3050                 uint32_t label, tc, ttl;
3051
3052                 if (n_tokens < 8)
3053                         return 0;
3054
3055                 if (strcmp(tokens[1], "unicast") == 0)
3056                         a->encap.mpls.unicast = 1;
3057                 else if (strcmp(tokens[1], "multicast") == 0)
3058                         a->encap.mpls.unicast = 0;
3059                 else
3060                         return 0;
3061
3062                 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
3063                         parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
3064                         strcmp(tokens[4], "label0") ||
3065                         parser_read_uint32(&label, tokens[5]) ||
3066                         (label > 0xFFFFF) ||
3067                         parser_read_uint32(&tc, tokens[6]) ||
3068                         (tc > 0x7) ||
3069                         parser_read_uint32(&ttl, tokens[7]) ||
3070                         (ttl > 0x3F))
3071                         return 0;
3072
3073                 a->encap.mpls.mpls[0].label = label;
3074                 a->encap.mpls.mpls[0].tc = tc;
3075                 a->encap.mpls.mpls[0].ttl = ttl;
3076
3077                 tokens += 8;
3078                 n_tokens -= 8;
3079
3080                 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
3081                         a->encap.mpls.mpls_count = 1;
3082                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3083                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3084                         return 1 + 8;
3085                 }
3086
3087                 if ((n_tokens < 4) ||
3088                         parser_read_uint32(&label, tokens[1]) ||
3089                         (label > 0xFFFFF) ||
3090                         parser_read_uint32(&tc, tokens[2]) ||
3091                         (tc > 0x7) ||
3092                         parser_read_uint32(&ttl, tokens[3]) ||
3093                         (ttl > 0x3F))
3094                         return 0;
3095
3096                 a->encap.mpls.mpls[1].label = label;
3097                 a->encap.mpls.mpls[1].tc = tc;
3098                 a->encap.mpls.mpls[1].ttl = ttl;
3099
3100                 tokens += 4;
3101                 n_tokens -= 4;
3102
3103                 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
3104                         a->encap.mpls.mpls_count = 2;
3105                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3106                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3107                         return 1 + 8 + 4;
3108                 }
3109
3110                 if ((n_tokens < 4) ||
3111                         parser_read_uint32(&label, tokens[1]) ||
3112                         (label > 0xFFFFF) ||
3113                         parser_read_uint32(&tc, tokens[2]) ||
3114                         (tc > 0x7) ||
3115                         parser_read_uint32(&ttl, tokens[3]) ||
3116                         (ttl > 0x3F))
3117                         return 0;
3118
3119                 a->encap.mpls.mpls[2].label = label;
3120                 a->encap.mpls.mpls[2].tc = tc;
3121                 a->encap.mpls.mpls[2].ttl = ttl;
3122
3123                 tokens += 4;
3124                 n_tokens -= 4;
3125
3126                 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
3127                         a->encap.mpls.mpls_count = 3;
3128                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3129                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3130                         return 1 + 8 + 4 + 4;
3131                 }
3132
3133                 if ((n_tokens < 4) ||
3134                         parser_read_uint32(&label, tokens[1]) ||
3135                         (label > 0xFFFFF) ||
3136                         parser_read_uint32(&tc, tokens[2]) ||
3137                         (tc > 0x7) ||
3138                         parser_read_uint32(&ttl, tokens[3]) ||
3139                         (ttl > 0x3F))
3140                         return 0;
3141
3142                 a->encap.mpls.mpls[3].label = label;
3143                 a->encap.mpls.mpls[3].tc = tc;
3144                 a->encap.mpls.mpls[3].ttl = ttl;
3145
3146                 a->encap.mpls.mpls_count = 4;
3147                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3148                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3149                 return 1 + 8 + 4 + 4 + 4;
3150         }
3151
3152         /* pppoe */
3153         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3154                 if ((n_tokens < 4) ||
3155                         parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3156                         parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3157                         parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3158                                 tokens[3]))
3159                         return 0;
3160
3161                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3162                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3163                 return 1 + 4;
3164         }
3165
3166         return 0;
3167 }
3168
3169 static uint32_t
3170 parse_table_action_nat(char **tokens,
3171         uint32_t n_tokens,
3172         struct table_rule_action *a)
3173 {
3174         if ((n_tokens < 4) ||
3175                 strcmp(tokens[0], "nat"))
3176                 return 0;
3177
3178         if (strcmp(tokens[1], "ipv4") == 0) {
3179                 struct in_addr addr;
3180                 uint16_t port;
3181
3182                 if (parse_ipv4_addr(tokens[2], &addr) ||
3183                         parser_read_uint16(&port, tokens[3]))
3184                         return 0;
3185
3186                 a->nat.ip_version = 1;
3187                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3188                 a->nat.port = port;
3189                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3190                 return 4;
3191         }
3192
3193         if (strcmp(tokens[1], "ipv6") == 0) {
3194                 struct in6_addr addr;
3195                 uint16_t port;
3196
3197                 if (parse_ipv6_addr(tokens[2], &addr) ||
3198                         parser_read_uint16(&port, tokens[3]))
3199                         return 0;
3200
3201                 a->nat.ip_version = 0;
3202                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3203                 a->nat.port = port;
3204                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3205                 return 4;
3206         }
3207
3208         return 0;
3209 }
3210
3211 static uint32_t
3212 parse_table_action_ttl(char **tokens,
3213         uint32_t n_tokens,
3214         struct table_rule_action *a)
3215 {
3216         if ((n_tokens < 2) ||
3217                 strcmp(tokens[0], "ttl"))
3218                 return 0;
3219
3220         if (strcmp(tokens[1], "dec") == 0)
3221                 a->ttl.decrement = 1;
3222         else if (strcmp(tokens[1], "keep") == 0)
3223                 a->ttl.decrement = 0;
3224         else
3225                 return 0;
3226
3227         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
3228         return 2;
3229 }
3230
3231 static uint32_t
3232 parse_table_action_stats(char **tokens,
3233         uint32_t n_tokens,
3234         struct table_rule_action *a)
3235 {
3236         if ((n_tokens < 1) ||
3237                 strcmp(tokens[0], "stats"))
3238                 return 0;
3239
3240         a->stats.n_packets = 0;
3241         a->stats.n_bytes = 0;
3242         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
3243         return 1;
3244 }
3245
3246 static uint32_t
3247 parse_table_action_time(char **tokens,
3248         uint32_t n_tokens,
3249         struct table_rule_action *a)
3250 {
3251         if ((n_tokens < 1) ||
3252                 strcmp(tokens[0], "time"))
3253                 return 0;
3254
3255         a->time.time = rte_rdtsc();
3256         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
3257         return 1;
3258 }
3259
3260 static uint32_t
3261 parse_table_action(char **tokens,
3262         uint32_t n_tokens,
3263         char *out,
3264         size_t out_size,
3265         struct table_rule_action *a)
3266 {
3267         uint32_t n_tokens0 = n_tokens;
3268
3269         memset(a, 0, sizeof(*a));
3270
3271         if ((n_tokens < 2) ||
3272                 strcmp(tokens[0], "action"))
3273                 return 0;
3274
3275         tokens++;
3276         n_tokens--;
3277
3278         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
3279                 uint32_t n;
3280
3281                 n = parse_table_action_fwd(tokens, n_tokens, a);
3282                 if (n == 0) {
3283                         snprintf(out, out_size, MSG_ARG_INVALID,
3284                                 "action fwd");
3285                         return 0;
3286                 }
3287
3288                 tokens += n;
3289                 n_tokens -= n;
3290         }
3291
3292         if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
3293                 uint32_t n;
3294
3295                 n = parse_table_action_balance(tokens, n_tokens, a);
3296                 if (n == 0) {
3297                         snprintf(out, out_size, MSG_ARG_INVALID,
3298                                 "action balance");
3299                         return 0;
3300                 }
3301
3302                 tokens += n;
3303                 n_tokens -= n;
3304         }
3305
3306         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
3307                 uint32_t n;
3308
3309                 n = parse_table_action_meter(tokens, n_tokens, a);
3310                 if (n == 0) {
3311                         snprintf(out, out_size, MSG_ARG_INVALID,
3312                                 "action meter");
3313                         return 0;
3314                 }
3315
3316                 tokens += n;
3317                 n_tokens -= n;
3318         }
3319
3320         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
3321                 uint32_t n;
3322
3323                 n = parse_table_action_tm(tokens, n_tokens, a);
3324                 if (n == 0) {
3325                         snprintf(out, out_size, MSG_ARG_INVALID,
3326                                 "action tm");
3327                         return 0;
3328                 }
3329
3330                 tokens += n;
3331                 n_tokens -= n;
3332         }
3333
3334         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
3335                 uint32_t n;
3336
3337                 n = parse_table_action_encap(tokens, n_tokens, a);
3338                 if (n == 0) {
3339                         snprintf(out, out_size, MSG_ARG_INVALID,
3340                                 "action encap");
3341                         return 0;
3342                 }
3343
3344                 tokens += n;
3345                 n_tokens -= n;
3346         }
3347
3348         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
3349                 uint32_t n;
3350
3351                 n = parse_table_action_nat(tokens, n_tokens, a);
3352                 if (n == 0) {
3353                         snprintf(out, out_size, MSG_ARG_INVALID,
3354                                 "action nat");
3355                         return 0;
3356                 }
3357
3358                 tokens += n;
3359                 n_tokens -= n;
3360         }
3361
3362         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
3363                 uint32_t n;
3364
3365                 n = parse_table_action_ttl(tokens, n_tokens, a);
3366                 if (n == 0) {
3367                         snprintf(out, out_size, MSG_ARG_INVALID,
3368                                 "action ttl");
3369                         return 0;
3370                 }
3371
3372                 tokens += n;
3373                 n_tokens -= n;
3374         }
3375
3376         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
3377                 uint32_t n;
3378
3379                 n = parse_table_action_stats(tokens, n_tokens, a);
3380                 if (n == 0) {
3381                         snprintf(out, out_size, MSG_ARG_INVALID,
3382                                 "action stats");
3383                         return 0;
3384                 }
3385
3386                 tokens += n;
3387                 n_tokens -= n;
3388         }
3389
3390         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
3391                 uint32_t n;
3392
3393                 n = parse_table_action_time(tokens, n_tokens, a);
3394                 if (n == 0) {
3395                         snprintf(out, out_size, MSG_ARG_INVALID,
3396                                 "action time");
3397                         return 0;
3398                 }
3399
3400                 tokens += n;
3401                 n_tokens -= n;
3402         }
3403
3404         if (n_tokens0 - n_tokens == 1) {
3405                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3406                 return 0;
3407         }
3408
3409         return n_tokens0 - n_tokens;
3410 }
3411
3412 /**
3413  * pipeline <pipeline_name> table <table_id> rule add
3414  *    match <match>
3415  *    action <table_action>
3416  */
3417 static void
3418 cmd_pipeline_table_rule_add(char **tokens,
3419         uint32_t n_tokens,
3420         char *out,
3421         size_t out_size)
3422 {
3423         struct table_rule_match m;
3424         struct table_rule_action a;
3425         char *pipeline_name;
3426         void *data;
3427         uint32_t table_id, t0, n_tokens_parsed;
3428         int status;
3429
3430         if (n_tokens < 8) {
3431                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3432                 return;
3433         }
3434
3435         pipeline_name = tokens[1];
3436
3437         if (strcmp(tokens[2], "table") != 0) {
3438                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3439                 return;
3440         }
3441
3442         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3443                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3444                 return;
3445         }
3446
3447         if (strcmp(tokens[4], "rule") != 0) {
3448                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3449                 return;
3450         }
3451
3452         if (strcmp(tokens[5], "add") != 0) {
3453                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3454                 return;
3455         }
3456
3457         t0 = 6;
3458
3459         /* match */
3460         n_tokens_parsed = parse_match(tokens + t0,
3461                 n_tokens - t0,
3462                 out,
3463                 out_size,
3464                 &m);
3465         if (n_tokens_parsed == 0)
3466                 return;
3467         t0 += n_tokens_parsed;
3468
3469         /* action */
3470         n_tokens_parsed = parse_table_action(tokens + t0,
3471                 n_tokens - t0,
3472                 out,
3473                 out_size,
3474                 &a);
3475         if (n_tokens_parsed == 0)
3476                 return;
3477         t0 += n_tokens_parsed;
3478
3479         if (t0 != n_tokens) {
3480                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
3481                 return;
3482         }
3483
3484         status = pipeline_table_rule_add(pipeline_name, table_id,
3485                 &m, &a, &data);
3486         if (status) {
3487                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3488                 return;
3489         }
3490 }
3491
3492 /**
3493  * pipeline <pipeline_name> table <table_id> rule add
3494  *    match
3495  *       default
3496  *    action
3497  *       fwd
3498  *          drop
3499  *          | port <port_id>
3500  *          | meta
3501  *          | table <table_id>
3502  */
3503 static void
3504 cmd_pipeline_table_rule_add_default(char **tokens,
3505         uint32_t n_tokens,
3506         char *out,
3507         size_t out_size)
3508 {
3509         struct table_rule_action action;
3510         void *data;
3511         char *pipeline_name;
3512         uint32_t table_id;
3513         int status;
3514
3515         if ((n_tokens != 11) && (n_tokens != 12)) {
3516                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3517                 return;
3518         }
3519
3520         pipeline_name = tokens[1];
3521
3522         if (strcmp(tokens[2], "table") != 0) {
3523                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3524                 return;
3525         }
3526
3527         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3528                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3529                 return;
3530         }
3531
3532         if (strcmp(tokens[4], "rule") != 0) {
3533                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3534                 return;
3535         }
3536
3537         if (strcmp(tokens[5], "add") != 0) {
3538                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3539                 return;
3540         }
3541
3542         if (strcmp(tokens[6], "match") != 0) {
3543                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3544                 return;
3545         }
3546
3547         if (strcmp(tokens[7], "default") != 0) {
3548                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3549                 return;
3550         }
3551
3552         if (strcmp(tokens[8], "action") != 0) {
3553                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3554                 return;
3555         }
3556
3557         if (strcmp(tokens[9], "fwd") != 0) {
3558                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
3559                 return;
3560         }
3561
3562         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
3563
3564         if (strcmp(tokens[10], "drop") == 0) {
3565                 if (n_tokens != 11) {
3566                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3567                         return;
3568                 }
3569
3570                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
3571         } else if (strcmp(tokens[10], "port") == 0) {
3572                 uint32_t id;
3573
3574                 if (n_tokens != 12) {
3575                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3576                         return;
3577                 }
3578
3579                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3580                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
3581                         return;
3582                 }
3583
3584                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
3585                 action.fwd.id = id;
3586         } else if (strcmp(tokens[10], "meta") == 0) {
3587                 if (n_tokens != 11) {
3588                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3589                         return;
3590                 }
3591
3592                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3593         } else if (strcmp(tokens[10], "table") == 0) {
3594                 uint32_t id;
3595
3596                 if (n_tokens != 12) {
3597                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3598                         return;
3599                 }
3600
3601                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3602                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3603                         return;
3604                 }
3605
3606                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
3607                 action.fwd.id = id;
3608         } else {
3609                 snprintf(out, out_size, MSG_ARG_INVALID,
3610                         "drop or port or meta or table");
3611                 return;
3612         }
3613
3614         status = pipeline_table_rule_add_default(pipeline_name,
3615                 table_id,
3616                 &action,
3617                 &data);
3618         if (status) {
3619                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3620                 return;
3621         }
3622 }
3623
3624 /**
3625  * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>
3626  *
3627  * File <file_name>:
3628  * - line format: match <match> action <action>
3629  */
3630 static int
3631 cli_rule_file_process(const char *file_name,
3632         size_t line_len_max,
3633         struct table_rule_match *m,
3634         struct table_rule_action *a,
3635         uint32_t *n_rules,
3636         uint32_t *line_number,
3637         char *out,
3638         size_t out_size);
3639
3640 static void
3641 cmd_pipeline_table_rule_add_bulk(char **tokens,
3642         uint32_t n_tokens,
3643         char *out,
3644         size_t out_size)
3645 {
3646         struct table_rule_match *match;
3647         struct table_rule_action *action;
3648         void **data;
3649         char *pipeline_name, *file_name;
3650         uint32_t table_id, n_rules, n_rules_parsed, line_number;
3651         int status;
3652
3653         if (n_tokens != 9) {
3654                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3655                 return;
3656         }
3657
3658         pipeline_name = tokens[1];
3659
3660         if (strcmp(tokens[2], "table") != 0) {
3661                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3662                 return;
3663         }
3664
3665         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3666                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3667                 return;
3668         }
3669
3670         if (strcmp(tokens[4], "rule") != 0) {
3671                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3672                 return;
3673         }
3674
3675         if (strcmp(tokens[5], "add") != 0) {
3676                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3677                 return;
3678         }
3679
3680         if (strcmp(tokens[6], "bulk") != 0) {
3681                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
3682                 return;
3683         }
3684
3685         file_name = tokens[7];
3686
3687         if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
3688                 (n_rules == 0)) {
3689                 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
3690                 return;
3691         }
3692
3693         /* Memory allocation. */
3694         match = calloc(n_rules, sizeof(struct table_rule_match));
3695         action = calloc(n_rules, sizeof(struct table_rule_action));
3696         data = calloc(n_rules, sizeof(void *));
3697         if ((match == NULL) || (action == NULL) || (data == NULL)) {
3698                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
3699                 free(data);
3700                 free(action);
3701                 free(match);
3702                 return;
3703         }
3704
3705         /* Load rule file */
3706         n_rules_parsed = n_rules;
3707         status = cli_rule_file_process(file_name,
3708                 1024,
3709                 match,
3710                 action,
3711                 &n_rules_parsed,
3712                 &line_number,
3713                 out,
3714                 out_size);
3715         if (status) {
3716                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
3717                 free(data);
3718                 free(action);
3719                 free(match);
3720                 return;
3721         }
3722         if (n_rules_parsed != n_rules) {
3723                 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
3724                 free(data);
3725                 free(action);
3726                 free(match);
3727                 return;
3728         }
3729
3730         /* Rule bulk add */
3731         status = pipeline_table_rule_add_bulk(pipeline_name,
3732                 table_id,
3733                 match,
3734                 action,
3735                 data,
3736                 &n_rules);
3737         if (status) {
3738                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3739                 free(data);
3740                 free(action);
3741                 free(match);
3742                 return;
3743         }
3744
3745         /* Memory free */
3746         free(data);
3747         free(action);
3748         free(match);
3749 }
3750
3751 /**
3752  * pipeline <pipeline_name> table <table_id> rule delete
3753  *    match <match>
3754  */
3755 static void
3756 cmd_pipeline_table_rule_delete(char **tokens,
3757         uint32_t n_tokens,
3758         char *out,
3759         size_t out_size)
3760 {
3761         struct table_rule_match m;
3762         char *pipeline_name;
3763         uint32_t table_id, n_tokens_parsed, t0;
3764         int status;
3765
3766         if (n_tokens < 8) {
3767                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3768                 return;
3769         }
3770
3771         pipeline_name = tokens[1];
3772
3773         if (strcmp(tokens[2], "table") != 0) {
3774                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3775                 return;
3776         }
3777
3778         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3779                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3780                 return;
3781         }
3782
3783         if (strcmp(tokens[4], "rule") != 0) {
3784                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3785                 return;
3786         }
3787
3788         if (strcmp(tokens[5], "delete") != 0) {
3789                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3790                 return;
3791         }
3792
3793         t0 = 6;
3794
3795         /* match */
3796         n_tokens_parsed = parse_match(tokens + t0,
3797                 n_tokens - t0,
3798                 out,
3799                 out_size,
3800                 &m);
3801         if (n_tokens_parsed == 0)
3802                 return;
3803         t0 += n_tokens_parsed;
3804
3805         if (n_tokens != t0) {
3806                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3807                 return;
3808         }
3809
3810         status = pipeline_table_rule_delete(pipeline_name,
3811                 table_id,
3812                 &m);
3813         if (status) {
3814                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3815                 return;
3816         }
3817 }
3818
3819 /**
3820  * pipeline <pipeline_name> table <table_id> rule delete
3821  *    match
3822  *       default
3823  */
3824 static void
3825 cmd_pipeline_table_rule_delete_default(char **tokens,
3826         uint32_t n_tokens,
3827         char *out,
3828         size_t out_size)
3829 {
3830         char *pipeline_name;
3831         uint32_t table_id;
3832         int status;
3833
3834         if (n_tokens != 8) {
3835                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3836                 return;
3837         }
3838
3839         pipeline_name = tokens[1];
3840
3841         if (strcmp(tokens[2], "table") != 0) {
3842                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3843                 return;
3844         }
3845
3846         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3847                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3848                 return;
3849         }
3850
3851         if (strcmp(tokens[4], "rule") != 0) {
3852                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3853                 return;
3854         }
3855
3856         if (strcmp(tokens[5], "delete") != 0) {
3857                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3858                 return;
3859         }
3860
3861         if (strcmp(tokens[6], "match") != 0) {
3862                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3863                 return;
3864         }
3865
3866         if (strcmp(tokens[7], "default") != 0) {
3867                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3868                 return;
3869         }
3870
3871         status = pipeline_table_rule_delete_default(pipeline_name,
3872                 table_id);
3873         if (status) {
3874                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3875                 return;
3876         }
3877 }
3878
3879 /**
3880  * pipeline <pipeline_name> table <table_id> rule read stats [clear]
3881  */
3882 static void
3883 cmd_pipeline_table_rule_stats_read(char **tokens,
3884         uint32_t n_tokens __rte_unused,
3885         char *out,
3886         size_t out_size)
3887 {
3888         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
3889 }
3890
3891 /**
3892  * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>
3893  *  add srtcm cir <cir> cbs <cbs> ebs <ebs>
3894  *  | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>
3895  */
3896 static void
3897 cmd_pipeline_table_meter_profile_add(char **tokens,
3898         uint32_t n_tokens,
3899         char *out,
3900         size_t out_size)
3901 {
3902         struct rte_table_action_meter_profile p;
3903         char *pipeline_name;
3904         uint32_t table_id, meter_profile_id;
3905         int status;
3906
3907         if (n_tokens < 9) {
3908                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3909                 return;
3910         }
3911
3912         pipeline_name = tokens[1];
3913
3914         if (strcmp(tokens[2], "table") != 0) {
3915                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
3916                 return;
3917         }
3918
3919         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3920                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3921                 return;
3922         }
3923
3924         if (strcmp(tokens[4], "meter") != 0) {
3925                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
3926                 return;
3927         }
3928
3929         if (strcmp(tokens[5], "profile") != 0) {
3930                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
3931                 return;
3932         }
3933
3934         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
3935                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
3936                 return;
3937         }
3938
3939         if (strcmp(tokens[7], "add") != 0) {
3940                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3941                 return;
3942         }
3943
3944         if (strcmp(tokens[8], "srtcm") == 0) {
3945                 if (n_tokens != 15) {
3946                         snprintf(out, out_size, MSG_ARG_MISMATCH,
3947                                 tokens[0]);
3948                         return;
3949                 }
3950
3951                 p.alg = RTE_TABLE_ACTION_METER_SRTCM;
3952
3953                 if (strcmp(tokens[9], "cir") != 0) {
3954                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
3955                         return;
3956                 }
3957
3958                 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
3959                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
3960                         return;
3961                 }
3962
3963                 if (strcmp(tokens[11], "cbs") != 0) {
3964                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
3965                         return;
3966                 }
3967
3968                 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
3969                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
3970                         return;
3971                 }
3972
3973                 if (strcmp(tokens[13], "ebs") != 0) {
3974                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
3975                         return;
3976                 }
3977
3978                 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
3979                         snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
3980                         return;
3981                 }
3982         } else if (strcmp(tokens[8], "trtcm") == 0) {
3983                 if (n_tokens != 17) {
3984                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3985                         return;
3986                 }
3987
3988                 p.alg = RTE_TABLE_ACTION_METER_TRTCM;
3989
3990                 if (strcmp(tokens[9], "cir") != 0) {
3991                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
3992                         return;
3993                 }
3994
3995                 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
3996                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
3997                         return;
3998                 }
3999
4000                 if (strcmp(tokens[11], "pir") != 0) {
4001                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
4002                         return;
4003                 }
4004
4005                 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
4006                         snprintf(out, out_size, MSG_ARG_INVALID, "pir");
4007                         return;
4008                 }
4009                 if (strcmp(tokens[13], "cbs") != 0) {
4010                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4011                         return;
4012                 }
4013
4014                 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
4015                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4016                         return;
4017                 }
4018
4019                 if (strcmp(tokens[15], "pbs") != 0) {
4020                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
4021                         return;
4022                 }
4023
4024                 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
4025                         snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
4026                         return;
4027                 }
4028         } else {
4029                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4030                 return;
4031         }
4032
4033         status = pipeline_table_mtr_profile_add(pipeline_name,
4034                 table_id,
4035                 meter_profile_id,
4036                 &p);
4037         if (status) {
4038                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4039                 return;
4040         }
4041 }
4042
4043 /**
4044  * pipeline <pipeline_name> table <table_id>
4045  *  meter profile <meter_profile_id> delete
4046  */
4047 static void
4048 cmd_pipeline_table_meter_profile_delete(char **tokens,
4049         uint32_t n_tokens,
4050         char *out,
4051         size_t out_size)
4052 {
4053         char *pipeline_name;
4054         uint32_t table_id, meter_profile_id;
4055         int status;
4056
4057         if (n_tokens != 8) {
4058                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4059                 return;
4060         }
4061
4062         pipeline_name = tokens[1];
4063
4064         if (strcmp(tokens[2], "table") != 0) {
4065                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4066                 return;
4067         }
4068
4069         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4070                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4071                 return;
4072         }
4073
4074         if (strcmp(tokens[4], "meter") != 0) {
4075                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4076                 return;
4077         }
4078
4079         if (strcmp(tokens[5], "profile") != 0) {
4080                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4081                 return;
4082         }
4083
4084         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4085                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4086                 return;
4087         }
4088
4089         if (strcmp(tokens[7], "delete") != 0) {
4090                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4091                 return;
4092         }
4093
4094         status = pipeline_table_mtr_profile_delete(pipeline_name,
4095                 table_id,
4096                 meter_profile_id);
4097         if (status) {
4098                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4099                 return;
4100         }
4101 }
4102
4103 /**
4104  * pipeline <pipeline_name> table <table_id> rule read meter [clear]
4105  */
4106 static void
4107 cmd_pipeline_table_rule_meter_read(char **tokens,
4108         uint32_t n_tokens __rte_unused,
4109         char *out,
4110         size_t out_size)
4111 {
4112         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4113 }
4114
4115 /**
4116  * pipeline <pipeline_name> table <table_id> dscp <file_name>
4117  *
4118  * File <file_name>:
4119  *  - exactly 64 lines
4120  *  - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r
4121  */
4122 static int
4123 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
4124         const char *file_name,
4125         uint32_t *line_number)
4126 {
4127         FILE *f = NULL;
4128         uint32_t dscp, l;
4129
4130         /* Check input arguments */
4131         if ((dscp_table == NULL) ||
4132                 (file_name == NULL) ||
4133                 (line_number == NULL)) {
4134                 if (line_number)
4135                         *line_number = 0;
4136                 return -EINVAL;
4137         }
4138
4139         /* Open input file */
4140         f = fopen(file_name, "r");
4141         if (f == NULL) {
4142                 *line_number = 0;
4143                 return -EINVAL;
4144         }
4145
4146         /* Read file */
4147         for (dscp = 0, l = 1; ; l++) {
4148                 char line[64];
4149                 char *tokens[3];
4150                 enum rte_meter_color color;
4151                 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
4152
4153                 if (fgets(line, sizeof(line), f) == NULL)
4154                         break;
4155
4156                 if (is_comment(line))
4157                         continue;
4158
4159                 if (parse_tokenize_string(line, tokens, &n_tokens)) {
4160                         *line_number = l;
4161                         fclose(f);
4162                         return -EINVAL;
4163                 }
4164
4165                 if (n_tokens == 0)
4166                         continue;
4167
4168                 if ((dscp >= RTE_DIM(dscp_table->entry)) ||
4169                         (n_tokens != RTE_DIM(tokens)) ||
4170                         parser_read_uint32(&tc_id, tokens[0]) ||
4171                         (tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
4172                         parser_read_uint32(&tc_queue_id, tokens[1]) ||
4173                         (tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
4174                         (strlen(tokens[2]) != 1)) {
4175                         *line_number = l;
4176                         fclose(f);
4177                         return -EINVAL;
4178                 }
4179
4180                 switch (tokens[2][0]) {
4181                 case 'g':
4182                 case 'G':
4183                         color = e_RTE_METER_GREEN;
4184                         break;
4185
4186                 case 'y':
4187                 case 'Y':
4188                         color = e_RTE_METER_YELLOW;
4189                         break;
4190
4191                 case 'r':
4192                 case 'R':
4193                         color = e_RTE_METER_RED;
4194                         break;
4195
4196                 default:
4197                         *line_number = l;
4198                         fclose(f);
4199                         return -EINVAL;
4200                 }
4201
4202                 dscp_table->entry[dscp].tc_id = tc_id;
4203                 dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
4204                 dscp_table->entry[dscp].color = color;
4205                 dscp++;
4206         }
4207
4208         /* Close file */
4209         fclose(f);
4210         return 0;
4211 }
4212
4213 static void
4214 cmd_pipeline_table_dscp(char **tokens,
4215         uint32_t n_tokens,
4216         char *out,
4217         size_t out_size)
4218 {
4219         struct rte_table_action_dscp_table dscp_table;
4220         char *pipeline_name, *file_name;
4221         uint32_t table_id, line_number;
4222         int status;
4223
4224         if (n_tokens != 6) {
4225                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4226                 return;
4227         }
4228
4229         pipeline_name = tokens[1];
4230
4231         if (strcmp(tokens[2], "table") != 0) {
4232                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4233                 return;
4234         }
4235
4236         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4237                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4238                 return;
4239         }
4240
4241         if (strcmp(tokens[4], "dscp") != 0) {
4242                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
4243                 return;
4244         }
4245
4246         file_name = tokens[5];
4247
4248         status = load_dscp_table(&dscp_table, file_name, &line_number);
4249         if (status) {
4250                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4251                 return;
4252         }
4253
4254         status = pipeline_table_dscp_table_update(pipeline_name,
4255                 table_id,
4256                 UINT64_MAX,
4257                 &dscp_table);
4258         if (status) {
4259                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4260                 return;
4261         }
4262 }
4263
4264 /**
4265  * pipeline <pipeline_name> table <table_id> rule read ttl [clear]
4266  */
4267 static void
4268 cmd_pipeline_table_rule_ttl_read(char **tokens,
4269         uint32_t n_tokens __rte_unused,
4270         char *out,
4271         size_t out_size)
4272 {
4273         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4274 }
4275
4276 /**
4277  * thread <thread_id> pipeline <pipeline_name> enable
4278  */
4279 static void
4280 cmd_thread_pipeline_enable(char **tokens,
4281         uint32_t n_tokens,
4282         char *out,
4283         size_t out_size)
4284 {
4285         char *pipeline_name;
4286         uint32_t thread_id;
4287         int status;
4288
4289         if (n_tokens != 5) {
4290                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4291                 return;
4292         }
4293
4294         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4295                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4296                 return;
4297         }
4298
4299         if (strcmp(tokens[2], "pipeline") != 0) {
4300                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4301                 return;
4302         }
4303
4304         pipeline_name = tokens[3];
4305
4306         if (strcmp(tokens[4], "enable") != 0) {
4307                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
4308                 return;
4309         }
4310
4311         status = thread_pipeline_enable(thread_id, pipeline_name);
4312         if (status) {
4313                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
4314                 return;
4315         }
4316 }
4317
4318 /**
4319  * thread <thread_id> pipeline <pipeline_name> disable
4320  */
4321 static void
4322 cmd_thread_pipeline_disable(char **tokens,
4323         uint32_t n_tokens,
4324         char *out,
4325         size_t out_size)
4326 {
4327         char *pipeline_name;
4328         uint32_t thread_id;
4329         int status;
4330
4331         if (n_tokens != 5) {
4332                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4333                 return;
4334         }
4335
4336         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4337                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4338                 return;
4339         }
4340
4341         if (strcmp(tokens[2], "pipeline") != 0) {
4342                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4343                 return;
4344         }
4345
4346         pipeline_name = tokens[3];
4347
4348         if (strcmp(tokens[4], "disable") != 0) {
4349                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
4350                 return;
4351         }
4352
4353         status = thread_pipeline_disable(thread_id, pipeline_name);
4354         if (status) {
4355                 snprintf(out, out_size, MSG_CMD_FAIL,
4356                         "thread pipeline disable");
4357                 return;
4358         }
4359 }
4360
4361 void
4362 cli_process(char *in, char *out, size_t out_size)
4363 {
4364         char *tokens[CMD_MAX_TOKENS];
4365         uint32_t n_tokens = RTE_DIM(tokens);
4366         int status;
4367
4368         if (is_comment(in))
4369                 return;
4370
4371         status = parse_tokenize_string(in, tokens, &n_tokens);
4372         if (status) {
4373                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
4374                 return;
4375         }
4376
4377         if (n_tokens == 0)
4378                 return;
4379
4380         if (strcmp(tokens[0], "mempool") == 0) {
4381                 cmd_mempool(tokens, n_tokens, out, out_size);
4382                 return;
4383         }
4384
4385         if (strcmp(tokens[0], "link") == 0) {
4386                 cmd_link(tokens, n_tokens, out, out_size);
4387                 return;
4388         }
4389
4390         if (strcmp(tokens[0], "swq") == 0) {
4391                 cmd_swq(tokens, n_tokens, out, out_size);
4392                 return;
4393         }
4394
4395         if (strcmp(tokens[0], "tmgr") == 0) {
4396                 if ((n_tokens >= 3) &&
4397                         (strcmp(tokens[1], "subport") == 0) &&
4398                         (strcmp(tokens[2], "profile") == 0)) {
4399                         cmd_tmgr_subport_profile(tokens, n_tokens,
4400                                 out, out_size);
4401                         return;
4402                 }
4403
4404                 if ((n_tokens >= 3) &&
4405                         (strcmp(tokens[1], "pipe") == 0) &&
4406                         (strcmp(tokens[2], "profile") == 0)) {
4407                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
4408                         return;
4409                 }
4410
4411                 if ((n_tokens >= 5) &&
4412                         (strcmp(tokens[2], "subport") == 0) &&
4413                         (strcmp(tokens[4], "profile") == 0)) {
4414                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
4415                         return;
4416                 }
4417
4418                 if ((n_tokens >= 5) &&
4419                         (strcmp(tokens[2], "subport") == 0) &&
4420                         (strcmp(tokens[4], "pipe") == 0)) {
4421                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
4422                         return;
4423                 }
4424
4425                 cmd_tmgr(tokens, n_tokens, out, out_size);
4426                 return;
4427         }
4428
4429         if (strcmp(tokens[0], "tap") == 0) {
4430                 cmd_tap(tokens, n_tokens, out, out_size);
4431                 return;
4432         }
4433
4434         if (strcmp(tokens[0], "kni") == 0) {
4435                 cmd_kni(tokens, n_tokens, out, out_size);
4436                 return;
4437         }
4438
4439         if (strcmp(tokens[0], "port") == 0) {
4440                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
4441                 return;
4442         }
4443
4444         if (strcmp(tokens[0], "table") == 0) {
4445                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
4446                 return;
4447         }
4448
4449         if (strcmp(tokens[0], "pipeline") == 0) {
4450                 if ((n_tokens >= 3) &&
4451                         (strcmp(tokens[2], "period") == 0)) {
4452                         cmd_pipeline(tokens, n_tokens, out, out_size);
4453                         return;
4454                 }
4455
4456                 if ((n_tokens >= 5) &&
4457                         (strcmp(tokens[2], "port") == 0) &&
4458                         (strcmp(tokens[3], "in") == 0) &&
4459                         (strcmp(tokens[4], "bsz") == 0)) {
4460                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
4461                         return;
4462                 }
4463
4464                 if ((n_tokens >= 5) &&
4465                         (strcmp(tokens[2], "port") == 0) &&
4466                         (strcmp(tokens[3], "out") == 0) &&
4467                         (strcmp(tokens[4], "bsz") == 0)) {
4468                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
4469                         return;
4470                 }
4471
4472                 if ((n_tokens >= 4) &&
4473                         (strcmp(tokens[2], "table") == 0) &&
4474                         (strcmp(tokens[3], "match") == 0)) {
4475                         cmd_pipeline_table(tokens, n_tokens, out, out_size);
4476                         return;
4477                 }
4478
4479                 if ((n_tokens >= 6) &&
4480                         (strcmp(tokens[2], "port") == 0) &&
4481                         (strcmp(tokens[3], "in") == 0) &&
4482                         (strcmp(tokens[5], "table") == 0)) {
4483                         cmd_pipeline_port_in_table(tokens, n_tokens,
4484                                 out, out_size);
4485                         return;
4486                 }
4487
4488                 if ((n_tokens >= 6) &&
4489                         (strcmp(tokens[2], "port") == 0) &&
4490                         (strcmp(tokens[3], "in") == 0) &&
4491                         (strcmp(tokens[5], "stats") == 0)) {
4492                         cmd_pipeline_port_in_stats(tokens, n_tokens,
4493                                 out, out_size);
4494                         return;
4495                 }
4496
4497                 if ((n_tokens >= 6) &&
4498                         (strcmp(tokens[2], "port") == 0) &&
4499                         (strcmp(tokens[3], "in") == 0) &&
4500                         (strcmp(tokens[5], "enable") == 0)) {
4501                         cmd_pipeline_port_in_enable(tokens, n_tokens,
4502                                 out, out_size);
4503                         return;
4504                 }
4505
4506                 if ((n_tokens >= 6) &&
4507                         (strcmp(tokens[2], "port") == 0) &&
4508                         (strcmp(tokens[3], "in") == 0) &&
4509                         (strcmp(tokens[5], "disable") == 0)) {
4510                         cmd_pipeline_port_in_disable(tokens, n_tokens,
4511                                 out, out_size);
4512                         return;
4513                 }
4514
4515                 if ((n_tokens >= 6) &&
4516                         (strcmp(tokens[2], "port") == 0) &&
4517                         (strcmp(tokens[3], "out") == 0) &&
4518                         (strcmp(tokens[5], "stats") == 0)) {
4519                         cmd_pipeline_port_out_stats(tokens, n_tokens,
4520                                 out, out_size);
4521                         return;
4522                 }
4523
4524                 if ((n_tokens >= 5) &&
4525                         (strcmp(tokens[2], "table") == 0) &&
4526                         (strcmp(tokens[4], "stats") == 0)) {
4527                         cmd_pipeline_table_stats(tokens, n_tokens,
4528                                 out, out_size);
4529                         return;
4530                 }
4531
4532                 if ((n_tokens >= 7) &&
4533                         (strcmp(tokens[2], "table") == 0) &&
4534                         (strcmp(tokens[4], "rule") == 0) &&
4535                         (strcmp(tokens[5], "add") == 0) &&
4536                         (strcmp(tokens[6], "match") == 0)) {
4537                         if ((n_tokens >= 8) &&
4538                                 (strcmp(tokens[7], "default") == 0)) {
4539                                 cmd_pipeline_table_rule_add_default(tokens,
4540                                         n_tokens, out, out_size);
4541                                 return;
4542                         }
4543
4544                         cmd_pipeline_table_rule_add(tokens, n_tokens,
4545                                 out, out_size);
4546                         return;
4547                 }
4548
4549                 if ((n_tokens >= 7) &&
4550                         (strcmp(tokens[2], "table") == 0) &&
4551                         (strcmp(tokens[4], "rule") == 0) &&
4552                         (strcmp(tokens[5], "add") == 0) &&
4553                         (strcmp(tokens[6], "bulk") == 0)) {
4554                         cmd_pipeline_table_rule_add_bulk(tokens,
4555                                 n_tokens, out, out_size);
4556                         return;
4557                 }
4558
4559                 if ((n_tokens >= 7) &&
4560                         (strcmp(tokens[2], "table") == 0) &&
4561                         (strcmp(tokens[4], "rule") == 0) &&
4562                         (strcmp(tokens[5], "delete") == 0) &&
4563                         (strcmp(tokens[6], "match") == 0)) {
4564                         if ((n_tokens >= 8) &&
4565                                 (strcmp(tokens[7], "default") == 0)) {
4566                                 cmd_pipeline_table_rule_delete_default(tokens,
4567                                         n_tokens, out, out_size);
4568                                 return;
4569                                 }
4570
4571                         cmd_pipeline_table_rule_delete(tokens, n_tokens,
4572                                 out, out_size);
4573                         return;
4574                 }
4575
4576                 if ((n_tokens >= 7) &&
4577                         (strcmp(tokens[2], "table") == 0) &&
4578                         (strcmp(tokens[4], "rule") == 0) &&
4579                         (strcmp(tokens[5], "read") == 0) &&
4580                         (strcmp(tokens[6], "stats") == 0)) {
4581                         cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
4582                                 out, out_size);
4583                         return;
4584                 }
4585
4586                 if ((n_tokens >= 8) &&
4587                         (strcmp(tokens[2], "table") == 0) &&
4588                         (strcmp(tokens[4], "meter") == 0) &&
4589                         (strcmp(tokens[5], "profile") == 0) &&
4590                         (strcmp(tokens[7], "add") == 0)) {
4591                         cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
4592                                 out, out_size);
4593                         return;
4594                 }
4595
4596                 if ((n_tokens >= 8) &&
4597                         (strcmp(tokens[2], "table") == 0) &&
4598                         (strcmp(tokens[4], "meter") == 0) &&
4599                         (strcmp(tokens[5], "profile") == 0) &&
4600                         (strcmp(tokens[7], "delete") == 0)) {
4601                         cmd_pipeline_table_meter_profile_delete(tokens,
4602                                 n_tokens, out, out_size);
4603                         return;
4604                 }
4605
4606                 if ((n_tokens >= 7) &&
4607                         (strcmp(tokens[2], "table") == 0) &&
4608                         (strcmp(tokens[4], "rule") == 0) &&
4609                         (strcmp(tokens[5], "read") == 0) &&
4610                         (strcmp(tokens[6], "meter") == 0)) {
4611                         cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
4612                                 out, out_size);
4613                         return;
4614                 }
4615
4616                 if ((n_tokens >= 5) &&
4617                         (strcmp(tokens[2], "table") == 0) &&
4618                         (strcmp(tokens[4], "dscp") == 0)) {
4619                         cmd_pipeline_table_dscp(tokens, n_tokens,
4620                                 out, out_size);
4621                         return;
4622                 }
4623
4624                 if ((n_tokens >= 7) &&
4625                         (strcmp(tokens[2], "table") == 0) &&
4626                         (strcmp(tokens[4], "rule") == 0) &&
4627                         (strcmp(tokens[5], "read") == 0) &&
4628                         (strcmp(tokens[6], "ttl") == 0)) {
4629                         cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
4630                                 out, out_size);
4631                         return;
4632                 }
4633         }
4634
4635         if (strcmp(tokens[0], "thread") == 0) {
4636                 if ((n_tokens >= 5) &&
4637                         (strcmp(tokens[4], "enable") == 0)) {
4638                         cmd_thread_pipeline_enable(tokens, n_tokens,
4639                                 out, out_size);
4640                         return;
4641                 }
4642
4643                 if ((n_tokens >= 5) &&
4644                         (strcmp(tokens[4], "disable") == 0)) {
4645                         cmd_thread_pipeline_disable(tokens, n_tokens,
4646                                 out, out_size);
4647                         return;
4648                 }
4649         }
4650
4651         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
4652 }
4653
4654 int
4655 cli_script_process(const char *file_name,
4656         size_t msg_in_len_max,
4657         size_t msg_out_len_max)
4658 {
4659         char *msg_in = NULL, *msg_out = NULL;
4660         FILE *f = NULL;
4661
4662         /* Check input arguments */
4663         if ((file_name == NULL) ||
4664                 (strlen(file_name) == 0) ||
4665                 (msg_in_len_max == 0) ||
4666                 (msg_out_len_max == 0))
4667                 return -EINVAL;
4668
4669         msg_in = malloc(msg_in_len_max + 1);
4670         msg_out = malloc(msg_out_len_max + 1);
4671         if ((msg_in == NULL) ||
4672                 (msg_out == NULL)) {
4673                 free(msg_out);
4674                 free(msg_in);
4675                 return -ENOMEM;
4676         }
4677
4678         /* Open input file */
4679         f = fopen(file_name, "r");
4680         if (f == NULL) {
4681                 free(msg_out);
4682                 free(msg_in);
4683                 return -EIO;
4684         }
4685
4686         /* Read file */
4687         for ( ; ; ) {
4688                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
4689                         break;
4690
4691                 printf("%s", msg_in);
4692                 msg_out[0] = 0;
4693
4694                 cli_process(msg_in,
4695                         msg_out,
4696                         msg_out_len_max);
4697
4698                 if (strlen(msg_out))
4699                         printf("%s", msg_out);
4700         }
4701
4702         /* Close file */
4703         fclose(f);
4704         free(msg_out);
4705         free(msg_in);
4706         return 0;
4707 }
4708
4709 static int
4710 cli_rule_file_process(const char *file_name,
4711         size_t line_len_max,
4712         struct table_rule_match *m,
4713         struct table_rule_action *a,
4714         uint32_t *n_rules,
4715         uint32_t *line_number,
4716         char *out,
4717         size_t out_size)
4718 {
4719         FILE *f = NULL;
4720         char *line = NULL;
4721         uint32_t rule_id, line_id;
4722         int status = 0;
4723
4724         /* Check input arguments */
4725         if ((file_name == NULL) ||
4726                 (strlen(file_name) == 0) ||
4727                 (line_len_max == 0)) {
4728                 *line_number = 0;
4729                 return -EINVAL;
4730         }
4731
4732         /* Memory allocation */
4733         line = malloc(line_len_max + 1);
4734         if (line == NULL) {
4735                 *line_number = 0;
4736                 return -ENOMEM;
4737         }
4738
4739         /* Open file */
4740         f = fopen(file_name, "r");
4741         if (f == NULL) {
4742                 *line_number = 0;
4743                 free(line);
4744                 return -EIO;
4745         }
4746
4747         /* Read file */
4748         for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
4749                 char *tokens[CMD_MAX_TOKENS];
4750                 uint32_t n_tokens, n_tokens_parsed, t0;
4751
4752                 /* Read next line from file. */
4753                 if (fgets(line, line_len_max + 1, f) == NULL)
4754                         break;
4755
4756                 /* Comment. */
4757                 if (is_comment(line))
4758                         continue;
4759
4760                 /* Parse line. */
4761                 n_tokens = RTE_DIM(tokens);
4762                 status = parse_tokenize_string(line, tokens, &n_tokens);
4763                 if (status) {
4764                         status = -EINVAL;
4765                         break;
4766                 }
4767
4768                 /* Empty line. */
4769                 if (n_tokens == 0)
4770                         continue;
4771                 t0 = 0;
4772
4773                 /* Rule match. */
4774                 n_tokens_parsed = parse_match(tokens + t0,
4775                         n_tokens - t0,
4776                         out,
4777                         out_size,
4778                         &m[rule_id]);
4779                 if (n_tokens_parsed == 0) {
4780                         status = -EINVAL;
4781                         break;
4782                 }
4783                 t0 += n_tokens_parsed;
4784
4785                 /* Rule action. */
4786                 n_tokens_parsed = parse_table_action(tokens + t0,
4787                         n_tokens - t0,
4788                         out,
4789                         out_size,
4790                         &a[rule_id]);
4791                 if (n_tokens_parsed == 0) {
4792                         status = -EINVAL;
4793                         break;
4794                 }
4795                 t0 += n_tokens_parsed;
4796
4797                 /* Line completed. */
4798                 if (t0 < n_tokens) {
4799                         status = -EINVAL;
4800                         break;
4801                 }
4802
4803                 /* Increment rule count */
4804                 rule_id++;
4805         }
4806
4807         /* Close file */
4808         fclose(f);
4809
4810         /* Memory free */
4811         free(line);
4812
4813         *n_rules = rule_id;
4814         *line_number = line_id;
4815         return status;
4816 }