examples/ip_pipeline: add load balance action command
[dpdk.git] / examples / ip_pipeline / cli.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <rte_common.h>
11 #include <rte_cycles.h>
12
13 #include "cli.h"
14 #include "kni.h"
15 #include "link.h"
16 #include "mempool.h"
17 #include "parser.h"
18 #include "pipeline.h"
19 #include "swq.h"
20 #include "tap.h"
21 #include "thread.h"
22 #include "tmgr.h"
23
24 #ifndef CMD_MAX_TOKENS
25 #define CMD_MAX_TOKENS     256
26 #endif
27
28 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
29 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
30 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
31 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
32 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
33 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
34 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
35 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
36 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
37 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
38 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
39
40 static int
41 is_comment(char *in)
42 {
43         if ((strlen(in) && index("!#%;", in[0])) ||
44                 (strncmp(in, "//", 2) == 0) ||
45                 (strncmp(in, "--", 2) == 0))
46                 return 1;
47
48         return 0;
49 }
50
51 /**
52  * mempool <mempool_name>
53  *  buffer <buffer_size>
54  *  pool <pool_size>
55  *  cache <cache_size>
56  *  cpu <cpu_id>
57  */
58 static void
59 cmd_mempool(char **tokens,
60         uint32_t n_tokens,
61         char *out,
62         size_t out_size)
63 {
64         struct mempool_params p;
65         char *name;
66         struct mempool *mempool;
67
68         if (n_tokens != 10) {
69                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
70                 return;
71         }
72
73         name = tokens[1];
74
75         if (strcmp(tokens[2], "buffer") != 0) {
76                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
77                 return;
78         }
79
80         if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
81                 snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
82                 return;
83         }
84
85         if (strcmp(tokens[4], "pool") != 0) {
86                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
87                 return;
88         }
89
90         if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
91                 snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
92                 return;
93         }
94
95         if (strcmp(tokens[6], "cache") != 0) {
96                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
97                 return;
98         }
99
100         if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
101                 snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
102                 return;
103         }
104
105         if (strcmp(tokens[8], "cpu") != 0) {
106                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
107                 return;
108         }
109
110         if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
111                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
112                 return;
113         }
114
115         mempool = mempool_create(name, &p);
116         if (mempool == NULL) {
117                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
118                 return;
119         }
120 }
121
122 /**
123  * link <link_name>
124  *  dev <device_name> | port <port_id>
125  *  rxq <n_queues> <queue_size> <mempool_name>
126  *  txq <n_queues> <queue_size>
127  *  promiscuous on | off
128  *  [rss <qid_0> ... <qid_n>]
129  */
130 static void
131 cmd_link(char **tokens,
132         uint32_t n_tokens,
133         char *out,
134         size_t out_size)
135 {
136         struct link_params p;
137         struct link_params_rss rss;
138         struct link *link;
139         char *name;
140
141         if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
142                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
143                 return;
144         }
145         name = tokens[1];
146
147         if (strcmp(tokens[2], "dev") == 0)
148                 p.dev_name = tokens[3];
149         else if (strcmp(tokens[2], "port") == 0) {
150                 p.dev_name = NULL;
151
152                 if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
153                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
154                         return;
155                 }
156         } else {
157                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
158                 return;
159         }
160
161         if (strcmp(tokens[4], "rxq") != 0) {
162                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
163                 return;
164         }
165
166         if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
167                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
168                 return;
169         }
170         if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
171                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
172                 return;
173         }
174
175         p.rx.mempool_name = tokens[7];
176
177         if (strcmp(tokens[8], "txq") != 0) {
178                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
179                 return;
180         }
181
182         if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
183                 snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
184                 return;
185         }
186
187         if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
188                 snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
189                 return;
190         }
191
192         if (strcmp(tokens[11], "promiscuous") != 0) {
193                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
194                 return;
195         }
196
197         if (strcmp(tokens[12], "on") == 0)
198                 p.promiscuous = 1;
199         else if (strcmp(tokens[12], "off") == 0)
200                 p.promiscuous = 0;
201         else {
202                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
203                 return;
204         }
205
206         /* RSS */
207         p.rx.rss = NULL;
208         if (n_tokens > 13) {
209                 uint32_t queue_id, i;
210
211                 if (strcmp(tokens[13], "rss") != 0) {
212                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
213                         return;
214                 }
215
216                 p.rx.rss = &rss;
217
218                 rss.n_queues = 0;
219                 for (i = 14; i < n_tokens; i++) {
220                         if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
221                                 snprintf(out, out_size, MSG_ARG_INVALID,
222                                         "queue_id");
223                                 return;
224                         }
225
226                         rss.queue_id[rss.n_queues] = queue_id;
227                         rss.n_queues++;
228                 }
229         }
230
231         link = link_create(name, &p);
232         if (link == NULL) {
233                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
234                 return;
235         }
236 }
237
238 /**
239  * swq <swq_name>
240  *  size <size>
241  *  cpu <cpu_id>
242  */
243 static void
244 cmd_swq(char **tokens,
245         uint32_t n_tokens,
246         char *out,
247         size_t out_size)
248 {
249         struct swq_params p;
250         char *name;
251         struct swq *swq;
252
253         if (n_tokens != 6) {
254                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
255                 return;
256         }
257
258         name = tokens[1];
259
260         if (strcmp(tokens[2], "size") != 0) {
261                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
262                 return;
263         }
264
265         if (parser_read_uint32(&p.size, tokens[3]) != 0) {
266                 snprintf(out, out_size, MSG_ARG_INVALID, "size");
267                 return;
268         }
269
270         if (strcmp(tokens[4], "cpu") != 0) {
271                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
272                 return;
273         }
274
275         if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
276                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
277                 return;
278         }
279
280         swq = swq_create(name, &p);
281         if (swq == NULL) {
282                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
283                 return;
284         }
285 }
286
287 /**
288  * tmgr subport profile
289  *  <tb_rate> <tb_size>
290  *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
291  *  <tc_period>
292  */
293 static void
294 cmd_tmgr_subport_profile(char **tokens,
295         uint32_t n_tokens,
296         char *out,
297         size_t out_size)
298 {
299         struct rte_sched_subport_params p;
300         int status, i;
301
302         if (n_tokens != 10) {
303                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
304                 return;
305         }
306
307         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
308                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
309                 return;
310         }
311
312         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
313                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
314                 return;
315         }
316
317         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
318                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
319                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
320                         return;
321                 }
322
323         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
324                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
325                 return;
326         }
327
328         status = tmgr_subport_profile_add(&p);
329         if (status != 0) {
330                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
331                 return;
332         }
333 }
334
335 /**
336  * tmgr pipe profile
337  *  <tb_rate> <tb_size>
338  *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
339  *  <tc_period>
340  *  <tc_ov_weight>
341  *  <wrr_weight0..15>
342  */
343 static void
344 cmd_tmgr_pipe_profile(char **tokens,
345         uint32_t n_tokens,
346         char *out,
347         size_t out_size)
348 {
349         struct rte_sched_pipe_params p;
350         int status, i;
351
352         if (n_tokens != 27) {
353                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
354                 return;
355         }
356
357         if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
358                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
359                 return;
360         }
361
362         if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
363                 snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
364                 return;
365         }
366
367         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
368                 if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
369                         snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
370                         return;
371                 }
372
373         if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
374                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
375                 return;
376         }
377
378 #ifdef RTE_SCHED_SUBPORT_TC_OV
379         if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) {
380                 snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
381                 return;
382         }
383 #endif
384
385         for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
386                 if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
387                         snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
388                         return;
389                 }
390
391         status = tmgr_pipe_profile_add(&p);
392         if (status != 0) {
393                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
394                 return;
395         }
396 }
397
398 /**
399  * tmgr <tmgr_name>
400  *  rate <rate>
401  *  spp <n_subports_per_port>
402  *  pps <n_pipes_per_subport>
403  *  qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>
404  *  fo <frame_overhead>
405  *  mtu <mtu>
406  *  cpu <cpu_id>
407  */
408 static void
409 cmd_tmgr(char **tokens,
410         uint32_t n_tokens,
411         char *out,
412         size_t out_size)
413 {
414         struct tmgr_port_params p;
415         char *name;
416         struct tmgr_port *tmgr_port;
417         int i;
418
419         if (n_tokens != 19) {
420                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
421                 return;
422         }
423
424         name = tokens[1];
425
426         if (strcmp(tokens[2], "rate") != 0) {
427                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
428                 return;
429         }
430
431         if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
432                 snprintf(out, out_size, MSG_ARG_INVALID, "rate");
433                 return;
434         }
435
436         if (strcmp(tokens[4], "spp") != 0) {
437                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
438                 return;
439         }
440
441         if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
442                 snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
443                 return;
444         }
445
446         if (strcmp(tokens[6], "pps") != 0) {
447                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
448                 return;
449         }
450
451         if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
452                 snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
453                 return;
454         }
455
456         if (strcmp(tokens[8], "qsize") != 0) {
457                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
458                 return;
459         }
460
461         for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
462                 if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
463                         snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
464                         return;
465                 }
466
467         if (strcmp(tokens[13], "fo") != 0) {
468                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
469                 return;
470         }
471
472         if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
473                 snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
474                 return;
475         }
476
477         if (strcmp(tokens[15], "mtu") != 0) {
478                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
479                 return;
480         }
481
482         if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
483                 snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
484                 return;
485         }
486
487         if (strcmp(tokens[17], "cpu") != 0) {
488                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
489                 return;
490         }
491
492         if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
493                 snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
494                 return;
495         }
496
497         tmgr_port = tmgr_port_create(name, &p);
498         if (tmgr_port == NULL) {
499                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
500                 return;
501         }
502 }
503
504 /**
505  * tmgr <tmgr_name> subport <subport_id>
506  *  profile <subport_profile_id>
507  */
508 static void
509 cmd_tmgr_subport(char **tokens,
510         uint32_t n_tokens,
511         char *out,
512         size_t out_size)
513 {
514         uint32_t subport_id, subport_profile_id;
515         int status;
516         char *name;
517
518         if (n_tokens != 6) {
519                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
520                 return;
521         }
522
523         name = tokens[1];
524
525         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
526                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
527                 return;
528         }
529
530         if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
531                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
532                 return;
533         }
534
535         status = tmgr_subport_config(name, subport_id, subport_profile_id);
536         if (status) {
537                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
538                 return;
539         }
540 }
541
542 /**
543  * tmgr <tmgr_name> subport <subport_id> pipe
544  *  from <pipe_id_first> to <pipe_id_last>
545  *  profile <pipe_profile_id>
546  */
547 static void
548 cmd_tmgr_subport_pipe(char **tokens,
549         uint32_t n_tokens,
550         char *out,
551         size_t out_size)
552 {
553         uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
554         int status;
555         char *name;
556
557         if (n_tokens != 11) {
558                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
559                 return;
560         }
561
562         name = tokens[1];
563
564         if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
565                 snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
566                 return;
567         }
568
569         if (strcmp(tokens[4], "pipe") != 0) {
570                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
571                 return;
572         }
573
574         if (strcmp(tokens[5], "from") != 0) {
575                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
576                 return;
577         }
578
579         if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
580                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
581                 return;
582         }
583
584         if (strcmp(tokens[7], "to") != 0) {
585                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
586                 return;
587         }
588
589         if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
590                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
591                 return;
592         }
593
594         if (strcmp(tokens[9], "profile") != 0) {
595                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
596                 return;
597         }
598
599         if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
600                 snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
601                 return;
602         }
603
604         status = tmgr_pipe_config(name, subport_id, pipe_id_first,
605                         pipe_id_last, pipe_profile_id);
606         if (status) {
607                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
608                 return;
609         }
610 }
611
612 /**
613  * tap <tap_name>
614  */
615 static void
616 cmd_tap(char **tokens,
617         uint32_t n_tokens,
618         char *out,
619         size_t out_size)
620 {
621         char *name;
622         struct tap *tap;
623
624         if (n_tokens != 2) {
625                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
626                 return;
627         }
628
629         name = tokens[1];
630
631         tap = tap_create(name);
632         if (tap == NULL) {
633                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
634                 return;
635         }
636 }
637
638 /**
639  * kni <kni_name>
640  *  link <link_name>
641  *  mempool <mempool_name>
642  *  [thread <thread_id>]
643  */
644 static void
645 cmd_kni(char **tokens,
646         uint32_t n_tokens,
647         char *out,
648         size_t out_size)
649 {
650         struct kni_params p;
651         char *name;
652         struct kni *kni;
653
654         if ((n_tokens != 6) && (n_tokens != 8)) {
655                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
656                 return;
657         }
658
659         name = tokens[1];
660
661         if (strcmp(tokens[2], "link") != 0) {
662                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
663                 return;
664         }
665
666         p.link_name = tokens[3];
667
668         if (strcmp(tokens[4], "mempool") != 0) {
669                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
670                 return;
671         }
672
673         p.mempool_name = tokens[5];
674
675         if (n_tokens == 8) {
676                 if (strcmp(tokens[6], "thread") != 0) {
677                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
678                         return;
679                 }
680
681                 if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
682                         snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
683                         return;
684                 }
685
686                 p.force_bind = 1;
687         } else
688                 p.force_bind = 0;
689
690         kni = kni_create(name, &p);
691         if (kni == NULL) {
692                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
693                 return;
694         }
695 }
696
697 /**
698  * port in action profile <profile_name>
699  *  [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]
700  *  [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]
701  */
702 static void
703 cmd_port_in_action_profile(char **tokens,
704         uint32_t n_tokens,
705         char *out,
706         size_t out_size)
707 {
708         struct port_in_action_profile_params p;
709         struct port_in_action_profile *ap;
710         char *name;
711         uint32_t t0;
712
713         memset(&p, 0, sizeof(p));
714
715         if (n_tokens < 5) {
716                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
717                 return;
718         }
719
720         if (strcmp(tokens[1], "in") != 0) {
721                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
722                 return;
723         }
724
725         if (strcmp(tokens[2], "action") != 0) {
726                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
727                 return;
728         }
729
730         if (strcmp(tokens[3], "profile") != 0) {
731                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
732                 return;
733         }
734
735         name = tokens[4];
736
737         t0 = 5;
738
739         if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) {
740                 uint32_t size;
741
742                 if (n_tokens < t0 + 10) {
743                         snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
744                         return;
745                 }
746
747                 if (strcmp(tokens[t0 + 1], "match") == 0)
748                         p.fltr.filter_on_match = 1;
749                 else if (strcmp(tokens[t0 + 1], "mismatch") == 0)
750                         p.fltr.filter_on_match = 0;
751                 else {
752                         snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
753                         return;
754                 }
755
756                 if (strcmp(tokens[t0 + 2], "offset") != 0) {
757                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
758                         return;
759                 }
760
761                 if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) {
762                         snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
763                         return;
764                 }
765
766                 if (strcmp(tokens[t0 + 4], "mask") != 0) {
767                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
768                         return;
769                 }
770
771                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
772                 if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) ||
773                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
774                         snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
775                         return;
776                 }
777
778                 if (strcmp(tokens[t0 + 6], "key") != 0) {
779                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
780                         return;
781                 }
782
783                 size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
784                 if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) ||
785                         (size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
786                         snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
787                         return;
788                 }
789
790                 if (strcmp(tokens[t0 + 8], "port") != 0) {
791                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
792                         return;
793                 }
794
795                 if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) {
796                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
797                         return;
798                 }
799
800                 p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
801                 t0 += 10;
802         } /* filter */
803
804         if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
805                 uint32_t i;
806
807                 if (n_tokens < t0 + 22) {
808                         snprintf(out, out_size, MSG_ARG_MISMATCH,
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
2318  *       pos
2319  *    | hash
2320  *       raw <key>
2321  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2322  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2323  *       | ipv4_addr <addr>
2324  *       | ipv6_addr <addr>
2325  *       | qinq <svlan> <cvlan>
2326  *    | lpm
2327  *       ipv4 | ipv6 <addr> <depth>
2328  */
2329 struct pkt_key_qinq {
2330         uint16_t ethertype_svlan;
2331         uint16_t svlan;
2332         uint16_t ethertype_cvlan;
2333         uint16_t cvlan;
2334 } __attribute__((__packed__));
2335
2336 struct pkt_key_ipv4_5tuple {
2337         uint8_t time_to_live;
2338         uint8_t proto;
2339         uint16_t hdr_checksum;
2340         uint32_t sa;
2341         uint32_t da;
2342         uint16_t sp;
2343         uint16_t dp;
2344 } __attribute__((__packed__));
2345
2346 struct pkt_key_ipv6_5tuple {
2347         uint16_t payload_length;
2348         uint8_t proto;
2349         uint8_t hop_limit;
2350         uint8_t sa[16];
2351         uint8_t da[16];
2352         uint16_t sp;
2353         uint16_t dp;
2354 } __attribute__((__packed__));
2355
2356 struct pkt_key_ipv4_addr {
2357         uint32_t addr;
2358 } __attribute__((__packed__));
2359
2360 struct pkt_key_ipv6_addr {
2361         uint8_t addr[16];
2362 } __attribute__((__packed__));
2363
2364 static uint32_t
2365 parse_match(char **tokens,
2366         uint32_t n_tokens,
2367         char *out,
2368         size_t out_size,
2369         struct table_rule_match *m)
2370 {
2371         memset(m, 0, sizeof(*m));
2372
2373         if (n_tokens < 2)
2374                 return 0;
2375
2376         if (strcmp(tokens[0], "match") != 0) {
2377                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2378                 return 0;
2379         }
2380
2381         if (strcmp(tokens[1], "acl") == 0) {
2382                 if (n_tokens < 14) {
2383                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2384                         return 0;
2385                 }
2386
2387                 m->match_type = TABLE_ACL;
2388
2389                 if (strcmp(tokens[2], "priority") != 0) {
2390                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
2391                         return 0;
2392                 }
2393
2394                 if (parser_read_uint32(&m->match.acl.priority,
2395                         tokens[3]) != 0) {
2396                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
2397                         return 0;
2398                 }
2399
2400                 if (strcmp(tokens[4], "ipv4") == 0) {
2401                         struct in_addr saddr, daddr;
2402
2403                         m->match.acl.ip_version = 1;
2404
2405                         if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
2406                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2407                                 return 0;
2408                         }
2409                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
2410
2411                         if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
2412                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2413                                 return 0;
2414                         }
2415                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
2416                 } else if (strcmp(tokens[4], "ipv6") == 0) {
2417                         struct in6_addr saddr, daddr;
2418
2419                         m->match.acl.ip_version = 0;
2420
2421                         if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
2422                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2423                                 return 0;
2424                         }
2425                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2426
2427                         if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2428                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2429                                 return 0;
2430                         }
2431                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
2432                 } else {
2433                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2434                                 "ipv4 or ipv6");
2435                         return 0;
2436                 }
2437
2438                 if (parser_read_uint32(&m->match.acl.sa_depth,
2439                         tokens[6]) != 0) {
2440                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
2441                         return 0;
2442                 }
2443
2444                 if (parser_read_uint32(&m->match.acl.da_depth,
2445                         tokens[8]) != 0) {
2446                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
2447                         return 0;
2448                 }
2449
2450                 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
2451                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
2452                         return 0;
2453                 }
2454
2455                 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
2456                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
2457                         return 0;
2458                 }
2459
2460                 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
2461                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
2462                         return 0;
2463                 }
2464
2465                 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
2466                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
2467                         return 0;
2468                 }
2469
2470                 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
2471                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
2472                         return 0;
2473                 }
2474
2475                 m->match.acl.proto_mask = 0xff;
2476
2477                 return 14;
2478         } /* acl */
2479
2480         if (strcmp(tokens[1], "array") == 0) {
2481                 if (n_tokens < 3) {
2482                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2483                         return 0;
2484                 }
2485
2486                 m->match_type = TABLE_ARRAY;
2487
2488                 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
2489                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
2490                         return 0;
2491                 }
2492
2493                 return 3;
2494         } /* array */
2495
2496         if (strcmp(tokens[1], "hash") == 0) {
2497                 if (n_tokens < 3) {
2498                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2499                         return 0;
2500                 }
2501
2502                 m->match_type = TABLE_HASH;
2503
2504                 if (strcmp(tokens[2], "raw") == 0) {
2505                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
2506
2507                         if (n_tokens < 4) {
2508                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2509                                         tokens[0]);
2510                                 return 0;
2511                         }
2512
2513                         if (parse_hex_string(tokens[3],
2514                                 m->match.hash.key, &key_size) != 0) {
2515                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
2516                                 return 0;
2517                         }
2518
2519                         return 4;
2520                 } /* hash raw */
2521
2522                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
2523                         struct pkt_key_ipv4_5tuple *ipv4 =
2524                                 (struct pkt_key_ipv4_5tuple *) m->match.hash.key;
2525                         struct in_addr saddr, daddr;
2526                         uint16_t sp, dp;
2527                         uint8_t proto;
2528
2529                         if (n_tokens < 8) {
2530                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2531                                         tokens[0]);
2532                                 return 0;
2533                         }
2534
2535                         if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
2536                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2537                                 return 0;
2538                         }
2539
2540                         if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
2541                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2542                                 return 0;
2543                         }
2544
2545                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2546                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2547                                 return 0;
2548                         }
2549
2550                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2551                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2552                                 return 0;
2553                         }
2554
2555                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2556                                 snprintf(out, out_size, MSG_ARG_INVALID,
2557                                         "proto");
2558                                 return 0;
2559                         }
2560
2561                         ipv4->sa = saddr.s_addr;
2562                         ipv4->da = daddr.s_addr;
2563                         ipv4->sp = rte_cpu_to_be_16(sp);
2564                         ipv4->dp = rte_cpu_to_be_16(dp);
2565                         ipv4->proto = proto;
2566
2567                         return 8;
2568                 } /* hash ipv4_5tuple */
2569
2570                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
2571                         struct pkt_key_ipv6_5tuple *ipv6 =
2572                                 (struct pkt_key_ipv6_5tuple *) m->match.hash.key;
2573                         struct in6_addr saddr, daddr;
2574                         uint16_t sp, dp;
2575                         uint8_t proto;
2576
2577                         if (n_tokens < 8) {
2578                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2579                                         tokens[0]);
2580                                 return 0;
2581                         }
2582
2583                         if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
2584                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2585                                 return 0;
2586                         }
2587
2588                         if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
2589                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2590                                 return 0;
2591                         }
2592
2593                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2594                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2595                                 return 0;
2596                         }
2597
2598                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2599                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2600                                 return 0;
2601                         }
2602
2603                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2604                                 snprintf(out, out_size, MSG_ARG_INVALID,
2605                                         "proto");
2606                                 return 0;
2607                         }
2608
2609                         memcpy(ipv6->sa, saddr.s6_addr, 16);
2610                         memcpy(ipv6->da, daddr.s6_addr, 16);
2611                         ipv6->sp = rte_cpu_to_be_16(sp);
2612                         ipv6->dp = rte_cpu_to_be_16(dp);
2613                         ipv6->proto = proto;
2614
2615                         return 8;
2616                 } /* hash ipv6_5tuple */
2617
2618                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
2619                         struct pkt_key_ipv4_addr *ipv4_addr =
2620                                 (struct pkt_key_ipv4_addr *) m->match.hash.key;
2621                         struct in_addr addr;
2622
2623                         if (n_tokens < 4) {
2624                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2625                                         tokens[0]);
2626                                 return 0;
2627                         }
2628
2629                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2630                                 snprintf(out, out_size, MSG_ARG_INVALID,
2631                                         "addr");
2632                                 return 0;
2633                         }
2634
2635                         ipv4_addr->addr = addr.s_addr;
2636
2637                         return 4;
2638                 } /* hash ipv4_addr */
2639
2640                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
2641                         struct pkt_key_ipv6_addr *ipv6_addr =
2642                                 (struct pkt_key_ipv6_addr *) m->match.hash.key;
2643                         struct in6_addr addr;
2644
2645                         if (n_tokens < 4) {
2646                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2647                                         tokens[0]);
2648                                 return 0;
2649                         }
2650
2651                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2652                                 snprintf(out, out_size, MSG_ARG_INVALID,
2653                                         "addr");
2654                                 return 0;
2655                         }
2656
2657                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
2658
2659                         return 4;
2660                 } /* hash ipv6_5tuple */
2661
2662                 if (strcmp(tokens[2], "qinq") == 0) {
2663                         struct pkt_key_qinq *qinq =
2664                                 (struct pkt_key_qinq *) m->match.hash.key;
2665                         uint16_t svlan, cvlan;
2666
2667                         if (n_tokens < 5) {
2668                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2669                                         tokens[0]);
2670                                 return 0;
2671                         }
2672
2673                         if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
2674                                 (svlan > 0xFFF)) {
2675                                 snprintf(out, out_size, MSG_ARG_INVALID,
2676                                         "svlan");
2677                                 return 0;
2678                         }
2679
2680                         if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
2681                                 (cvlan > 0xFFF)) {
2682                                 snprintf(out, out_size, MSG_ARG_INVALID,
2683                                         "cvlan");
2684                                 return 0;
2685                         }
2686
2687                         qinq->svlan = rte_cpu_to_be_16(svlan);
2688                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
2689
2690                         return 5;
2691                 } /* hash qinq */
2692
2693                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2694                 return 0;
2695         } /* hash */
2696
2697         if (strcmp(tokens[1], "lpm") == 0) {
2698                 if (n_tokens < 5) {
2699                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2700                         return 0;
2701                 }
2702
2703                 m->match_type = TABLE_LPM;
2704
2705                 if (strcmp(tokens[2], "ipv4") == 0) {
2706                         struct in_addr addr;
2707
2708                         m->match.lpm.ip_version = 1;
2709
2710                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2711                                 snprintf(out, out_size, MSG_ARG_INVALID,
2712                                         "addr");
2713                                 return 0;
2714                         }
2715
2716                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
2717                 } else if (strcmp(tokens[2], "ipv6") == 0) {
2718                         struct in6_addr addr;
2719
2720                         m->match.lpm.ip_version = 0;
2721
2722                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2723                                 snprintf(out, out_size, MSG_ARG_INVALID,
2724                                         "addr");
2725                                 return 0;
2726                         }
2727
2728                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
2729                 } else {
2730                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2731                                 "ipv4 or ipv6");
2732                         return 0;
2733                 }
2734
2735                 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
2736                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
2737                         return 0;
2738                 }
2739
2740                 return 5;
2741         } /* lpm */
2742
2743         snprintf(out, out_size, MSG_ARG_MISMATCH,
2744                 "acl or array or hash or lpm");
2745         return 0;
2746 }
2747
2748 /**
2749  * table_action ::=
2750  *
2751  * action
2752  *    fwd
2753  *       drop
2754  *       | port <port_id>
2755  *       | meta
2756  *       | table <table_id>
2757  *    [balance <out0> ... <out7>]
2758  *    [meter
2759  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2760  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2761  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2762  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
2763  *    [tm subport <subport_id> pipe <pipe_id>]
2764  *    [encap
2765  *       ether <da> <sa>
2766  *       | vlan <da> <sa> <pcp> <dei> <vid>
2767  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
2768  *       | mpls unicast | multicast
2769  *          <da> <sa>
2770  *          label0 <label> <tc> <ttl>
2771  *          [label1 <label> <tc> <ttl>
2772  *          [label2 <label> <tc> <ttl>
2773  *          [label3 <label> <tc> <ttl>]]]
2774  *       | pppoe <da> <sa> <session_id>]
2775  *    [nat ipv4 | ipv6 <addr> <port>]
2776  *    [ttl dec | keep]
2777  *    [stats]
2778  *    [time]
2779  *
2780  * where:
2781  *    <pa> ::= g | y | r | drop
2782  */
2783 static uint32_t
2784 parse_table_action_fwd(char **tokens,
2785         uint32_t n_tokens,
2786         struct table_rule_action *a)
2787 {
2788         if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
2789                 return 0;
2790
2791         tokens++;
2792         n_tokens--;
2793
2794         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
2795                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
2796                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2797                 return 1 + 1;
2798         }
2799
2800         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
2801                 uint32_t id;
2802
2803                 if ((n_tokens < 2) ||
2804                         parser_read_uint32(&id, tokens[1]))
2805                         return 0;
2806
2807                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
2808                 a->fwd.id = id;
2809                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2810                 return 1 + 2;
2811         }
2812
2813         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
2814                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
2815                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2816                 return 1 + 1;
2817         }
2818
2819         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
2820                 uint32_t id;
2821
2822                 if ((n_tokens < 2) ||
2823                         parser_read_uint32(&id, tokens[1]))
2824                         return 0;
2825
2826                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
2827                 a->fwd.id = id;
2828                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2829                 return 1 + 2;
2830         }
2831
2832         return 0;
2833 }
2834
2835 static uint32_t
2836 parse_table_action_balance(char **tokens,
2837         uint32_t n_tokens,
2838         struct table_rule_action *a)
2839 {
2840         uint32_t i;
2841
2842         if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0))
2843                 return 0;
2844
2845         tokens++;
2846         n_tokens--;
2847
2848         if (n_tokens < RTE_TABLE_ACTION_LB_KEY_SIZE_MAX)
2849                 return 0;
2850
2851         for (i = 0; i < RTE_TABLE_ACTION_LB_KEY_SIZE_MAX; i++)
2852                 if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
2853                         return 0;
2854
2855         a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
2856         return 1 + RTE_TABLE_ACTION_LB_KEY_SIZE_MAX;
2857
2858 }
2859
2860 static int
2861 parse_policer_action(char *token, enum rte_table_action_policer *a)
2862 {
2863         if (strcmp(token, "g") == 0) {
2864                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
2865                 return 0;
2866         }
2867
2868         if (strcmp(token, "y") == 0) {
2869                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
2870                 return 0;
2871         }
2872
2873         if (strcmp(token, "r") == 0) {
2874                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
2875                 return 0;
2876         }
2877
2878         if (strcmp(token, "drop") == 0) {
2879                 *a = RTE_TABLE_ACTION_POLICER_DROP;
2880                 return 0;
2881         }
2882
2883         return -1;
2884 }
2885
2886 static uint32_t
2887 parse_table_action_meter_tc(char **tokens,
2888         uint32_t n_tokens,
2889         struct rte_table_action_mtr_tc_params *mtr)
2890 {
2891         if ((n_tokens < 9) ||
2892                 strcmp(tokens[0], "meter") ||
2893                 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
2894                 strcmp(tokens[2], "policer") ||
2895                 strcmp(tokens[3], "g") ||
2896                 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
2897                 strcmp(tokens[5], "y") ||
2898                 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
2899                 strcmp(tokens[7], "r") ||
2900                 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
2901                 return 0;
2902
2903         return 9;
2904 }
2905
2906 static uint32_t
2907 parse_table_action_meter(char **tokens,
2908         uint32_t n_tokens,
2909         struct table_rule_action *a)
2910 {
2911         if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
2912                 return 0;
2913
2914         tokens++;
2915         n_tokens--;
2916
2917         if ((n_tokens < 10) ||
2918                 strcmp(tokens[0], "tc0") ||
2919                 (parse_table_action_meter_tc(tokens + 1,
2920                         n_tokens - 1,
2921                         &a->mtr.mtr[0]) == 0))
2922                 return 0;
2923
2924         tokens += 10;
2925         n_tokens -= 10;
2926
2927         if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
2928                 a->mtr.tc_mask = 1;
2929                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2930                 return 1 + 10;
2931         }
2932
2933         if ((n_tokens < 30) ||
2934                 (parse_table_action_meter_tc(tokens + 1,
2935                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
2936                 strcmp(tokens[10], "tc2") ||
2937                 (parse_table_action_meter_tc(tokens + 11,
2938                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
2939                 strcmp(tokens[20], "tc3") ||
2940                 (parse_table_action_meter_tc(tokens + 21,
2941                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
2942                 return 0;
2943
2944         a->mtr.tc_mask = 0xF;
2945         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2946         return 1 + 10 + 3 * 10;
2947 }
2948
2949 static uint32_t
2950 parse_table_action_tm(char **tokens,
2951         uint32_t n_tokens,
2952         struct table_rule_action *a)
2953 {
2954         uint32_t subport_id, pipe_id;
2955
2956         if ((n_tokens < 5) ||
2957                 strcmp(tokens[0], "tm") ||
2958                 strcmp(tokens[1], "subport") ||
2959                 parser_read_uint32(&subport_id, tokens[2]) ||
2960                 strcmp(tokens[3], "pipe") ||
2961                 parser_read_uint32(&pipe_id, tokens[4]))
2962                 return 0;
2963
2964         a->tm.subport_id = subport_id;
2965         a->tm.pipe_id = pipe_id;
2966         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
2967         return 5;
2968 }
2969
2970 static uint32_t
2971 parse_table_action_encap(char **tokens,
2972         uint32_t n_tokens,
2973         struct table_rule_action *a)
2974 {
2975         if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
2976                 return 0;
2977
2978         tokens++;
2979         n_tokens--;
2980
2981         /* ether */
2982         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
2983                 if ((n_tokens < 3) ||
2984                         parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
2985                         parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
2986                         return 0;
2987
2988                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
2989                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2990                 return 1 + 3;
2991         }
2992
2993         /* vlan */
2994         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
2995                 uint32_t pcp, dei, vid;
2996
2997                 if ((n_tokens < 6) ||
2998                         parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
2999                         parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
3000                         parser_read_uint32(&pcp, tokens[3]) ||
3001                         (pcp > 0x7) ||
3002                         parser_read_uint32(&dei, tokens[4]) ||
3003                         (dei > 0x1) ||
3004                         parser_read_uint32(&vid, tokens[5]) ||
3005                         (vid > 0xFFF))
3006                         return 0;
3007
3008                 a->encap.vlan.vlan.pcp = pcp & 0x7;
3009                 a->encap.vlan.vlan.dei = dei & 0x1;
3010                 a->encap.vlan.vlan.vid = vid & 0xFFF;
3011                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
3012                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3013                 return 1 + 6;
3014         }
3015
3016         /* qinq */
3017         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
3018                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
3019                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3020
3021                 if ((n_tokens < 9) ||
3022                         parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
3023                         parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
3024                         parser_read_uint32(&svlan_pcp, tokens[3]) ||
3025                         (svlan_pcp > 0x7) ||
3026                         parser_read_uint32(&svlan_dei, tokens[4]) ||
3027                         (svlan_dei > 0x1) ||
3028                         parser_read_uint32(&svlan_vid, tokens[5]) ||
3029                         (svlan_vid > 0xFFF) ||
3030                         parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3031                         (cvlan_pcp > 0x7) ||
3032                         parser_read_uint32(&cvlan_dei, tokens[7]) ||
3033                         (cvlan_dei > 0x1) ||
3034                         parser_read_uint32(&cvlan_vid, tokens[8]) ||
3035                         (cvlan_vid > 0xFFF))
3036                         return 0;
3037
3038                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
3039                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
3040                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
3041                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
3042                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
3043                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
3044                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
3045                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3046                 return 1 + 9;
3047         }
3048
3049         /* mpls */
3050         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
3051                 uint32_t label, tc, ttl;
3052
3053                 if (n_tokens < 8)
3054                         return 0;
3055
3056                 if (strcmp(tokens[1], "unicast") == 0)
3057                         a->encap.mpls.unicast = 1;
3058                 else if (strcmp(tokens[1], "multicast") == 0)
3059                         a->encap.mpls.unicast = 0;
3060                 else
3061                         return 0;
3062
3063                 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
3064                         parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
3065                         strcmp(tokens[4], "label0") ||
3066                         parser_read_uint32(&label, tokens[5]) ||
3067                         (label > 0xFFFFF) ||
3068                         parser_read_uint32(&tc, tokens[6]) ||
3069                         (tc > 0x7) ||
3070                         parser_read_uint32(&ttl, tokens[7]) ||
3071                         (ttl > 0x3F))
3072                         return 0;
3073
3074                 a->encap.mpls.mpls[0].label = label;
3075                 a->encap.mpls.mpls[0].tc = tc;
3076                 a->encap.mpls.mpls[0].ttl = ttl;
3077
3078                 tokens += 8;
3079                 n_tokens -= 8;
3080
3081                 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
3082                         a->encap.mpls.mpls_count = 1;
3083                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3084                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3085                         return 1 + 8;
3086                 }
3087
3088                 if ((n_tokens < 4) ||
3089                         parser_read_uint32(&label, tokens[1]) ||
3090                         (label > 0xFFFFF) ||
3091                         parser_read_uint32(&tc, tokens[2]) ||
3092                         (tc > 0x7) ||
3093                         parser_read_uint32(&ttl, tokens[3]) ||
3094                         (ttl > 0x3F))
3095                         return 0;
3096
3097                 a->encap.mpls.mpls[1].label = label;
3098                 a->encap.mpls.mpls[1].tc = tc;
3099                 a->encap.mpls.mpls[1].ttl = ttl;
3100
3101                 tokens += 4;
3102                 n_tokens -= 4;
3103
3104                 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
3105                         a->encap.mpls.mpls_count = 2;
3106                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3107                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3108                         return 1 + 8 + 4;
3109                 }
3110
3111                 if ((n_tokens < 4) ||
3112                         parser_read_uint32(&label, tokens[1]) ||
3113                         (label > 0xFFFFF) ||
3114                         parser_read_uint32(&tc, tokens[2]) ||
3115                         (tc > 0x7) ||
3116                         parser_read_uint32(&ttl, tokens[3]) ||
3117                         (ttl > 0x3F))
3118                         return 0;
3119
3120                 a->encap.mpls.mpls[2].label = label;
3121                 a->encap.mpls.mpls[2].tc = tc;
3122                 a->encap.mpls.mpls[2].ttl = ttl;
3123
3124                 tokens += 4;
3125                 n_tokens -= 4;
3126
3127                 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
3128                         a->encap.mpls.mpls_count = 3;
3129                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3130                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3131                         return 1 + 8 + 4 + 4;
3132                 }
3133
3134                 if ((n_tokens < 4) ||
3135                         parser_read_uint32(&label, tokens[1]) ||
3136                         (label > 0xFFFFF) ||
3137                         parser_read_uint32(&tc, tokens[2]) ||
3138                         (tc > 0x7) ||
3139                         parser_read_uint32(&ttl, tokens[3]) ||
3140                         (ttl > 0x3F))
3141                         return 0;
3142
3143                 a->encap.mpls.mpls[3].label = label;
3144                 a->encap.mpls.mpls[3].tc = tc;
3145                 a->encap.mpls.mpls[3].ttl = ttl;
3146
3147                 a->encap.mpls.mpls_count = 4;
3148                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3149                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3150                 return 1 + 8 + 4 + 4 + 4;
3151         }
3152
3153         /* pppoe */
3154         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3155                 if ((n_tokens < 4) ||
3156                         parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3157                         parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3158                         parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3159                                 tokens[3]))
3160                         return 0;
3161
3162                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3163                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3164                 return 1 + 4;
3165         }
3166
3167         return 0;
3168 }
3169
3170 static uint32_t
3171 parse_table_action_nat(char **tokens,
3172         uint32_t n_tokens,
3173         struct table_rule_action *a)
3174 {
3175         if ((n_tokens < 4) ||
3176                 strcmp(tokens[0], "nat"))
3177                 return 0;
3178
3179         if (strcmp(tokens[1], "ipv4") == 0) {
3180                 struct in_addr addr;
3181                 uint16_t port;
3182
3183                 if (parse_ipv4_addr(tokens[2], &addr) ||
3184                         parser_read_uint16(&port, tokens[3]))
3185                         return 0;
3186
3187                 a->nat.ip_version = 1;
3188                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3189                 a->nat.port = port;
3190                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3191                 return 4;
3192         }
3193
3194         if (strcmp(tokens[1], "ipv6") == 0) {
3195                 struct in6_addr addr;
3196                 uint16_t port;
3197
3198                 if (parse_ipv6_addr(tokens[2], &addr) ||
3199                         parser_read_uint16(&port, tokens[3]))
3200                         return 0;
3201
3202                 a->nat.ip_version = 0;
3203                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3204                 a->nat.port = port;
3205                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3206                 return 4;
3207         }
3208
3209         return 0;
3210 }
3211
3212 static uint32_t
3213 parse_table_action_ttl(char **tokens,
3214         uint32_t n_tokens,
3215         struct table_rule_action *a)
3216 {
3217         if ((n_tokens < 2) ||
3218                 strcmp(tokens[0], "ttl"))
3219                 return 0;
3220
3221         if (strcmp(tokens[1], "dec") == 0)
3222                 a->ttl.decrement = 1;
3223         else if (strcmp(tokens[1], "keep") == 0)
3224                 a->ttl.decrement = 0;
3225         else
3226                 return 0;
3227
3228         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
3229         return 2;
3230 }
3231
3232 static uint32_t
3233 parse_table_action_stats(char **tokens,
3234         uint32_t n_tokens,
3235         struct table_rule_action *a)
3236 {
3237         if ((n_tokens < 1) ||
3238                 strcmp(tokens[0], "stats"))
3239                 return 0;
3240
3241         a->stats.n_packets = 0;
3242         a->stats.n_bytes = 0;
3243         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
3244         return 1;
3245 }
3246
3247 static uint32_t
3248 parse_table_action_time(char **tokens,
3249         uint32_t n_tokens,
3250         struct table_rule_action *a)
3251 {
3252         if ((n_tokens < 1) ||
3253                 strcmp(tokens[0], "time"))
3254                 return 0;
3255
3256         a->time.time = rte_rdtsc();
3257         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
3258         return 1;
3259 }
3260
3261 static uint32_t
3262 parse_table_action(char **tokens,
3263         uint32_t n_tokens,
3264         char *out,
3265         size_t out_size,
3266         struct table_rule_action *a)
3267 {
3268         uint32_t n_tokens0 = n_tokens;
3269
3270         memset(a, 0, sizeof(*a));
3271
3272         if ((n_tokens < 2) ||
3273                 strcmp(tokens[0], "action"))
3274                 return 0;
3275
3276         tokens++;
3277         n_tokens--;
3278
3279         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
3280                 uint32_t n;
3281
3282                 n = parse_table_action_fwd(tokens, n_tokens, a);
3283                 if (n == 0) {
3284                         snprintf(out, out_size, MSG_ARG_INVALID,
3285                                 "action fwd");
3286                         return 0;
3287                 }
3288
3289                 tokens += n;
3290                 n_tokens -= n;
3291         }
3292
3293         if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
3294                 uint32_t n;
3295
3296                 n = parse_table_action_balance(tokens, n_tokens, a);
3297                 if (n == 0) {
3298                         snprintf(out, out_size, MSG_ARG_INVALID,
3299                                 "action balance");
3300                         return 0;
3301                 }
3302
3303                 tokens += n;
3304                 n_tokens -= n;
3305         }
3306
3307         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
3308                 uint32_t n;
3309
3310                 n = parse_table_action_meter(tokens, n_tokens, a);
3311                 if (n == 0) {
3312                         snprintf(out, out_size, MSG_ARG_INVALID,
3313                                 "action meter");
3314                         return 0;
3315                 }
3316
3317                 tokens += n;
3318                 n_tokens -= n;
3319         }
3320
3321         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
3322                 uint32_t n;
3323
3324                 n = parse_table_action_tm(tokens, n_tokens, a);
3325                 if (n == 0) {
3326                         snprintf(out, out_size, MSG_ARG_INVALID,
3327                                 "action tm");
3328                         return 0;
3329                 }
3330
3331                 tokens += n;
3332                 n_tokens -= n;
3333         }
3334
3335         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
3336                 uint32_t n;
3337
3338                 n = parse_table_action_encap(tokens, n_tokens, a);
3339                 if (n == 0) {
3340                         snprintf(out, out_size, MSG_ARG_INVALID,
3341                                 "action encap");
3342                         return 0;
3343                 }
3344
3345                 tokens += n;
3346                 n_tokens -= n;
3347         }
3348
3349         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
3350                 uint32_t n;
3351
3352                 n = parse_table_action_nat(tokens, n_tokens, a);
3353                 if (n == 0) {
3354                         snprintf(out, out_size, MSG_ARG_INVALID,
3355                                 "action nat");
3356                         return 0;
3357                 }
3358
3359                 tokens += n;
3360                 n_tokens -= n;
3361         }
3362
3363         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
3364                 uint32_t n;
3365
3366                 n = parse_table_action_ttl(tokens, n_tokens, a);
3367                 if (n == 0) {
3368                         snprintf(out, out_size, MSG_ARG_INVALID,
3369                                 "action ttl");
3370                         return 0;
3371                 }
3372
3373                 tokens += n;
3374                 n_tokens -= n;
3375         }
3376
3377         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
3378                 uint32_t n;
3379
3380                 n = parse_table_action_stats(tokens, n_tokens, a);
3381                 if (n == 0) {
3382                         snprintf(out, out_size, MSG_ARG_INVALID,
3383                                 "action stats");
3384                         return 0;
3385                 }
3386
3387                 tokens += n;
3388                 n_tokens -= n;
3389         }
3390
3391         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
3392                 uint32_t n;
3393
3394                 n = parse_table_action_time(tokens, n_tokens, a);
3395                 if (n == 0) {
3396                         snprintf(out, out_size, MSG_ARG_INVALID,
3397                                 "action time");
3398                         return 0;
3399                 }
3400
3401                 tokens += n;
3402                 n_tokens -= n;
3403         }
3404
3405         if (n_tokens0 - n_tokens == 1) {
3406                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3407                 return 0;
3408         }
3409
3410         return n_tokens0 - n_tokens;
3411 }
3412
3413 /**
3414  * pipeline <pipeline_name> table <table_id> rule add
3415  *    match <match>
3416  *    action <table_action>
3417  */
3418 static void
3419 cmd_pipeline_table_rule_add(char **tokens,
3420         uint32_t n_tokens,
3421         char *out,
3422         size_t out_size)
3423 {
3424         struct table_rule_match m;
3425         struct table_rule_action a;
3426         char *pipeline_name;
3427         void *data;
3428         uint32_t table_id, t0, n_tokens_parsed;
3429         int status;
3430
3431         if (n_tokens < 8) {
3432                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3433                 return;
3434         }
3435
3436         pipeline_name = tokens[1];
3437
3438         if (strcmp(tokens[2], "table") != 0) {
3439                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3440                 return;
3441         }
3442
3443         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3444                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3445                 return;
3446         }
3447
3448         if (strcmp(tokens[4], "rule") != 0) {
3449                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3450                 return;
3451         }
3452
3453         if (strcmp(tokens[5], "add") != 0) {
3454                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3455                 return;
3456         }
3457
3458         t0 = 6;
3459
3460         /* match */
3461         n_tokens_parsed = parse_match(tokens + t0,
3462                 n_tokens - t0,
3463                 out,
3464                 out_size,
3465                 &m);
3466         if (n_tokens_parsed == 0)
3467                 return;
3468         t0 += n_tokens_parsed;
3469
3470         /* action */
3471         n_tokens_parsed = parse_table_action(tokens + t0,
3472                 n_tokens - t0,
3473                 out,
3474                 out_size,
3475                 &a);
3476         if (n_tokens_parsed == 0)
3477                 return;
3478         t0 += n_tokens_parsed;
3479
3480         if (t0 != n_tokens) {
3481                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
3482                 return;
3483         }
3484
3485         status = pipeline_table_rule_add(pipeline_name, table_id,
3486                 &m, &a, &data);
3487         if (status) {
3488                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3489                 return;
3490         }
3491 }
3492
3493 /**
3494  * pipeline <pipeline_name> table <table_id> rule add
3495  *    match
3496  *       default
3497  *    action
3498  *       fwd
3499  *          drop
3500  *          | port <port_id>
3501  *          | meta
3502  *          | table <table_id>
3503  */
3504 static void
3505 cmd_pipeline_table_rule_add_default(char **tokens,
3506         uint32_t n_tokens,
3507         char *out,
3508         size_t out_size)
3509 {
3510         struct table_rule_action action;
3511         void *data;
3512         char *pipeline_name;
3513         uint32_t table_id;
3514         int status;
3515
3516         if ((n_tokens != 11) && (n_tokens != 12)) {
3517                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3518                 return;
3519         }
3520
3521         pipeline_name = tokens[1];
3522
3523         if (strcmp(tokens[2], "table") != 0) {
3524                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3525                 return;
3526         }
3527
3528         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3529                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3530                 return;
3531         }
3532
3533         if (strcmp(tokens[4], "rule") != 0) {
3534                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3535                 return;
3536         }
3537
3538         if (strcmp(tokens[5], "add") != 0) {
3539                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3540                 return;
3541         }
3542
3543         if (strcmp(tokens[6], "match") != 0) {
3544                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3545                 return;
3546         }
3547
3548         if (strcmp(tokens[7], "default") != 0) {
3549                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3550                 return;
3551         }
3552
3553         if (strcmp(tokens[8], "action") != 0) {
3554                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3555                 return;
3556         }
3557
3558         if (strcmp(tokens[9], "fwd") != 0) {
3559                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
3560                 return;
3561         }
3562
3563         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
3564
3565         if (strcmp(tokens[10], "drop") == 0) {
3566                 if (n_tokens != 11) {
3567                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3568                         return;
3569                 }
3570
3571                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
3572         } else if (strcmp(tokens[10], "port") == 0) {
3573                 uint32_t id;
3574
3575                 if (n_tokens != 12) {
3576                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3577                         return;
3578                 }
3579
3580                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3581                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
3582                         return;
3583                 }
3584
3585                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
3586                 action.fwd.id = id;
3587         } else if (strcmp(tokens[10], "meta") == 0) {
3588                 if (n_tokens != 11) {
3589                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3590                         return;
3591                 }
3592
3593                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3594         } else if (strcmp(tokens[10], "table") == 0) {
3595                 uint32_t id;
3596
3597                 if (n_tokens != 12) {
3598                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3599                         return;
3600                 }
3601
3602                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3603                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3604                         return;
3605                 }
3606
3607                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
3608                 action.fwd.id = id;
3609         } else {
3610                 snprintf(out, out_size, MSG_ARG_INVALID,
3611                         "drop or port or meta or table");
3612                 return;
3613         }
3614
3615         status = pipeline_table_rule_add_default(pipeline_name,
3616                 table_id,
3617                 &action,
3618                 &data);
3619         if (status) {
3620                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3621                 return;
3622         }
3623 }
3624
3625 /**
3626  * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>
3627  *
3628  * File <file_name>:
3629  * - line format: match <match> action <action>
3630  */
3631 static int
3632 cli_rule_file_process(const char *file_name,
3633         size_t line_len_max,
3634         struct table_rule_match *m,
3635         struct table_rule_action *a,
3636         uint32_t *n_rules,
3637         uint32_t *line_number,
3638         char *out,
3639         size_t out_size);
3640
3641 static void
3642 cmd_pipeline_table_rule_add_bulk(char **tokens,
3643         uint32_t n_tokens,
3644         char *out,
3645         size_t out_size)
3646 {
3647         struct table_rule_match *match;
3648         struct table_rule_action *action;
3649         void **data;
3650         char *pipeline_name, *file_name;
3651         uint32_t table_id, n_rules, n_rules_parsed, line_number;
3652         int status;
3653
3654         if (n_tokens != 9) {
3655                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3656                 return;
3657         }
3658
3659         pipeline_name = tokens[1];
3660
3661         if (strcmp(tokens[2], "table") != 0) {
3662                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3663                 return;
3664         }
3665
3666         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3667                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3668                 return;
3669         }
3670
3671         if (strcmp(tokens[4], "rule") != 0) {
3672                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3673                 return;
3674         }
3675
3676         if (strcmp(tokens[5], "add") != 0) {
3677                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3678                 return;
3679         }
3680
3681         if (strcmp(tokens[6], "bulk") != 0) {
3682                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
3683                 return;
3684         }
3685
3686         file_name = tokens[7];
3687
3688         if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
3689                 (n_rules == 0)) {
3690                 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
3691                 return;
3692         }
3693
3694         /* Memory allocation. */
3695         match = calloc(n_rules, sizeof(struct table_rule_match));
3696         action = calloc(n_rules, sizeof(struct table_rule_action));
3697         data = calloc(n_rules, sizeof(void *));
3698         if ((match == NULL) || (action == NULL) || (data == NULL)) {
3699                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
3700                 free(data);
3701                 free(action);
3702                 free(match);
3703                 return;
3704         }
3705
3706         /* Load rule file */
3707         n_rules_parsed = n_rules;
3708         status = cli_rule_file_process(file_name,
3709                 1024,
3710                 match,
3711                 action,
3712                 &n_rules_parsed,
3713                 &line_number,
3714                 out,
3715                 out_size);
3716         if (status) {
3717                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
3718                 free(data);
3719                 free(action);
3720                 free(match);
3721                 return;
3722         }
3723         if (n_rules_parsed != n_rules) {
3724                 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
3725                 free(data);
3726                 free(action);
3727                 free(match);
3728                 return;
3729         }
3730
3731         /* Rule bulk add */
3732         status = pipeline_table_rule_add_bulk(pipeline_name,
3733                 table_id,
3734                 match,
3735                 action,
3736                 data,
3737                 &n_rules);
3738         if (status) {
3739                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3740                 free(data);
3741                 free(action);
3742                 free(match);
3743                 return;
3744         }
3745
3746         /* Memory free */
3747         free(data);
3748         free(action);
3749         free(match);
3750 }
3751
3752 /**
3753  * pipeline <pipeline_name> table <table_id> rule delete
3754  *    match <match>
3755  */
3756 static void
3757 cmd_pipeline_table_rule_delete(char **tokens,
3758         uint32_t n_tokens,
3759         char *out,
3760         size_t out_size)
3761 {
3762         struct table_rule_match m;
3763         char *pipeline_name;
3764         uint32_t table_id, n_tokens_parsed, t0;
3765         int status;
3766
3767         if (n_tokens < 8) {
3768                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3769                 return;
3770         }
3771
3772         pipeline_name = tokens[1];
3773
3774         if (strcmp(tokens[2], "table") != 0) {
3775                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3776                 return;
3777         }
3778
3779         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3780                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3781                 return;
3782         }
3783
3784         if (strcmp(tokens[4], "rule") != 0) {
3785                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3786                 return;
3787         }
3788
3789         if (strcmp(tokens[5], "delete") != 0) {
3790                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3791                 return;
3792         }
3793
3794         t0 = 6;
3795
3796         /* match */
3797         n_tokens_parsed = parse_match(tokens + t0,
3798                 n_tokens - t0,
3799                 out,
3800                 out_size,
3801                 &m);
3802         if (n_tokens_parsed == 0)
3803                 return;
3804         t0 += n_tokens_parsed;
3805
3806         if (n_tokens != t0) {
3807                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3808                 return;
3809         }
3810
3811         status = pipeline_table_rule_delete(pipeline_name,
3812                 table_id,
3813                 &m);
3814         if (status) {
3815                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3816                 return;
3817         }
3818 }
3819
3820 /**
3821  * pipeline <pipeline_name> table <table_id> rule delete
3822  *    match
3823  *       default
3824  */
3825 static void
3826 cmd_pipeline_table_rule_delete_default(char **tokens,
3827         uint32_t n_tokens,
3828         char *out,
3829         size_t out_size)
3830 {
3831         char *pipeline_name;
3832         uint32_t table_id;
3833         int status;
3834
3835         if (n_tokens != 8) {
3836                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3837                 return;
3838         }
3839
3840         pipeline_name = tokens[1];
3841
3842         if (strcmp(tokens[2], "table") != 0) {
3843                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3844                 return;
3845         }
3846
3847         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3848                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3849                 return;
3850         }
3851
3852         if (strcmp(tokens[4], "rule") != 0) {
3853                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3854                 return;
3855         }
3856
3857         if (strcmp(tokens[5], "delete") != 0) {
3858                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3859                 return;
3860         }
3861
3862         if (strcmp(tokens[6], "match") != 0) {
3863                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3864                 return;
3865         }
3866
3867         if (strcmp(tokens[7], "default") != 0) {
3868                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3869                 return;
3870         }
3871
3872         status = pipeline_table_rule_delete_default(pipeline_name,
3873                 table_id);
3874         if (status) {
3875                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3876                 return;
3877         }
3878 }
3879
3880 /**
3881  * pipeline <pipeline_name> table <table_id> rule read stats [clear]
3882  */
3883 static void
3884 cmd_pipeline_table_rule_stats_read(char **tokens,
3885         uint32_t n_tokens __rte_unused,
3886         char *out,
3887         size_t out_size)
3888 {
3889         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
3890 }
3891
3892 /**
3893  * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>
3894  *  add srtcm cir <cir> cbs <cbs> ebs <ebs>
3895  *  | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>
3896  */
3897 static void
3898 cmd_pipeline_table_meter_profile_add(char **tokens,
3899         uint32_t n_tokens,
3900         char *out,
3901         size_t out_size)
3902 {
3903         struct rte_table_action_meter_profile p;
3904         char *pipeline_name;
3905         uint32_t table_id, meter_profile_id;
3906         int status;
3907
3908         if (n_tokens < 9) {
3909                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3910                 return;
3911         }
3912
3913         pipeline_name = tokens[1];
3914
3915         if (strcmp(tokens[2], "table") != 0) {
3916                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
3917                 return;
3918         }
3919
3920         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3921                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3922                 return;
3923         }
3924
3925         if (strcmp(tokens[4], "meter") != 0) {
3926                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
3927                 return;
3928         }
3929
3930         if (strcmp(tokens[5], "profile") != 0) {
3931                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
3932                 return;
3933         }
3934
3935         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
3936                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
3937                 return;
3938         }
3939
3940         if (strcmp(tokens[7], "add") != 0) {
3941                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3942                 return;
3943         }
3944
3945         if (strcmp(tokens[8], "srtcm") == 0) {
3946                 if (n_tokens != 15) {
3947                         snprintf(out, out_size, MSG_ARG_MISMATCH,
3948                                 tokens[0]);
3949                         return;
3950                 }
3951
3952                 p.alg = RTE_TABLE_ACTION_METER_SRTCM;
3953
3954                 if (strcmp(tokens[9], "cir") != 0) {
3955                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
3956                         return;
3957                 }
3958
3959                 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
3960                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
3961                         return;
3962                 }
3963
3964                 if (strcmp(tokens[11], "cbs") != 0) {
3965                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
3966                         return;
3967                 }
3968
3969                 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
3970                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
3971                         return;
3972                 }
3973
3974                 if (strcmp(tokens[13], "ebs") != 0) {
3975                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
3976                         return;
3977                 }
3978
3979                 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
3980                         snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
3981                         return;
3982                 }
3983         } else if (strcmp(tokens[8], "trtcm") == 0) {
3984                 if (n_tokens != 17) {
3985                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3986                         return;
3987                 }
3988
3989                 p.alg = RTE_TABLE_ACTION_METER_TRTCM;
3990
3991                 if (strcmp(tokens[9], "cir") != 0) {
3992                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
3993                         return;
3994                 }
3995
3996                 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
3997                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
3998                         return;
3999                 }
4000
4001                 if (strcmp(tokens[11], "pir") != 0) {
4002                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
4003                         return;
4004                 }
4005
4006                 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
4007                         snprintf(out, out_size, MSG_ARG_INVALID, "pir");
4008                         return;
4009                 }
4010                 if (strcmp(tokens[13], "cbs") != 0) {
4011                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4012                         return;
4013                 }
4014
4015                 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
4016                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4017                         return;
4018                 }
4019
4020                 if (strcmp(tokens[15], "pbs") != 0) {
4021                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
4022                         return;
4023                 }
4024
4025                 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
4026                         snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
4027                         return;
4028                 }
4029         } else {
4030                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4031                 return;
4032         }
4033
4034         status = pipeline_table_mtr_profile_add(pipeline_name,
4035                 table_id,
4036                 meter_profile_id,
4037                 &p);
4038         if (status) {
4039                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4040                 return;
4041         }
4042 }
4043
4044 /**
4045  * pipeline <pipeline_name> table <table_id>
4046  *  meter profile <meter_profile_id> delete
4047  */
4048 static void
4049 cmd_pipeline_table_meter_profile_delete(char **tokens,
4050         uint32_t n_tokens,
4051         char *out,
4052         size_t out_size)
4053 {
4054         char *pipeline_name;
4055         uint32_t table_id, meter_profile_id;
4056         int status;
4057
4058         if (n_tokens != 8) {
4059                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4060                 return;
4061         }
4062
4063         pipeline_name = tokens[1];
4064
4065         if (strcmp(tokens[2], "table") != 0) {
4066                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4067                 return;
4068         }
4069
4070         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4071                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4072                 return;
4073         }
4074
4075         if (strcmp(tokens[4], "meter") != 0) {
4076                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4077                 return;
4078         }
4079
4080         if (strcmp(tokens[5], "profile") != 0) {
4081                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4082                 return;
4083         }
4084
4085         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4086                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4087                 return;
4088         }
4089
4090         if (strcmp(tokens[7], "delete") != 0) {
4091                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4092                 return;
4093         }
4094
4095         status = pipeline_table_mtr_profile_delete(pipeline_name,
4096                 table_id,
4097                 meter_profile_id);
4098         if (status) {
4099                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4100                 return;
4101         }
4102 }
4103
4104 /**
4105  * pipeline <pipeline_name> table <table_id> rule read meter [clear]
4106  */
4107 static void
4108 cmd_pipeline_table_rule_meter_read(char **tokens,
4109         uint32_t n_tokens __rte_unused,
4110         char *out,
4111         size_t out_size)
4112 {
4113         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4114 }
4115
4116 /**
4117  * pipeline <pipeline_name> table <table_id> dscp <file_name>
4118  *
4119  * File <file_name>:
4120  *  - exactly 64 lines
4121  *  - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r
4122  */
4123 static int
4124 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
4125         const char *file_name,
4126         uint32_t *line_number)
4127 {
4128         FILE *f = NULL;
4129         uint32_t dscp, l;
4130
4131         /* Check input arguments */
4132         if ((dscp_table == NULL) ||
4133                 (file_name == NULL) ||
4134                 (line_number == NULL)) {
4135                 if (line_number)
4136                         *line_number = 0;
4137                 return -EINVAL;
4138         }
4139
4140         /* Open input file */
4141         f = fopen(file_name, "r");
4142         if (f == NULL) {
4143                 *line_number = 0;
4144                 return -EINVAL;
4145         }
4146
4147         /* Read file */
4148         for (dscp = 0, l = 1; ; l++) {
4149                 char line[64];
4150                 char *tokens[3];
4151                 enum rte_meter_color color;
4152                 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
4153
4154                 if (fgets(line, sizeof(line), f) == NULL)
4155                         break;
4156
4157                 if (is_comment(line))
4158                         continue;
4159
4160                 if (parse_tokenize_string(line, tokens, &n_tokens)) {
4161                         *line_number = l;
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                         return -EINVAL;
4177                 }
4178
4179                 switch (tokens[2][0]) {
4180                 case 'g':
4181                 case 'G':
4182                         color = e_RTE_METER_GREEN;
4183                         break;
4184
4185                 case 'y':
4186                 case 'Y':
4187                         color = e_RTE_METER_YELLOW;
4188                         break;
4189
4190                 case 'r':
4191                 case 'R':
4192                         color = e_RTE_METER_RED;
4193                         break;
4194
4195                 default:
4196                         *line_number = l;
4197                         return -EINVAL;
4198                 }
4199
4200                 dscp_table->entry[dscp].tc_id = tc_id;
4201                 dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
4202                 dscp_table->entry[dscp].color = color;
4203                 dscp++;
4204         }
4205
4206         /* Close file */
4207         fclose(f);
4208         return 0;
4209 }
4210
4211 static void
4212 cmd_pipeline_table_dscp(char **tokens,
4213         uint32_t n_tokens,
4214         char *out,
4215         size_t out_size)
4216 {
4217         struct rte_table_action_dscp_table dscp_table;
4218         char *pipeline_name, *file_name;
4219         uint32_t table_id, line_number;
4220         int status;
4221
4222         if (n_tokens != 6) {
4223                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4224                 return;
4225         }
4226
4227         pipeline_name = tokens[1];
4228
4229         if (strcmp(tokens[2], "table") != 0) {
4230                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4231                 return;
4232         }
4233
4234         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4235                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4236                 return;
4237         }
4238
4239         if (strcmp(tokens[4], "dscp") != 0) {
4240                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
4241                 return;
4242         }
4243
4244         file_name = tokens[5];
4245
4246         status = load_dscp_table(&dscp_table, file_name, &line_number);
4247         if (status) {
4248                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4249                 return;
4250         }
4251
4252         status = pipeline_table_dscp_table_update(pipeline_name,
4253                 table_id,
4254                 UINT64_MAX,
4255                 &dscp_table);
4256         if (status) {
4257                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4258                 return;
4259         }
4260 }
4261
4262 /**
4263  * pipeline <pipeline_name> table <table_id> rule read ttl [clear]
4264  */
4265 static void
4266 cmd_pipeline_table_rule_ttl_read(char **tokens,
4267         uint32_t n_tokens __rte_unused,
4268         char *out,
4269         size_t out_size)
4270 {
4271         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4272 }
4273
4274 /**
4275  * thread <thread_id> pipeline <pipeline_name> enable
4276  */
4277 static void
4278 cmd_thread_pipeline_enable(char **tokens,
4279         uint32_t n_tokens,
4280         char *out,
4281         size_t out_size)
4282 {
4283         char *pipeline_name;
4284         uint32_t thread_id;
4285         int status;
4286
4287         if (n_tokens != 5) {
4288                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4289                 return;
4290         }
4291
4292         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4293                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4294                 return;
4295         }
4296
4297         if (strcmp(tokens[2], "pipeline") != 0) {
4298                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4299                 return;
4300         }
4301
4302         pipeline_name = tokens[3];
4303
4304         if (strcmp(tokens[4], "enable") != 0) {
4305                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
4306                 return;
4307         }
4308
4309         status = thread_pipeline_enable(thread_id, pipeline_name);
4310         if (status) {
4311                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
4312                 return;
4313         }
4314 }
4315
4316 /**
4317  * thread <thread_id> pipeline <pipeline_name> disable
4318  */
4319 static void
4320 cmd_thread_pipeline_disable(char **tokens,
4321         uint32_t n_tokens,
4322         char *out,
4323         size_t out_size)
4324 {
4325         char *pipeline_name;
4326         uint32_t thread_id;
4327         int status;
4328
4329         if (n_tokens != 5) {
4330                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4331                 return;
4332         }
4333
4334         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4335                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4336                 return;
4337         }
4338
4339         if (strcmp(tokens[2], "pipeline") != 0) {
4340                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4341                 return;
4342         }
4343
4344         pipeline_name = tokens[3];
4345
4346         if (strcmp(tokens[4], "disable") != 0) {
4347                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
4348                 return;
4349         }
4350
4351         status = thread_pipeline_disable(thread_id, pipeline_name);
4352         if (status) {
4353                 snprintf(out, out_size, MSG_CMD_FAIL,
4354                         "thread pipeline disable");
4355                 return;
4356         }
4357 }
4358
4359 void
4360 cli_process(char *in, char *out, size_t out_size)
4361 {
4362         char *tokens[CMD_MAX_TOKENS];
4363         uint32_t n_tokens = RTE_DIM(tokens);
4364         int status;
4365
4366         if (is_comment(in))
4367                 return;
4368
4369         status = parse_tokenize_string(in, tokens, &n_tokens);
4370         if (status) {
4371                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
4372                 return;
4373         }
4374
4375         if (n_tokens == 0)
4376                 return;
4377
4378         if (strcmp(tokens[0], "mempool") == 0) {
4379                 cmd_mempool(tokens, n_tokens, out, out_size);
4380                 return;
4381         }
4382
4383         if (strcmp(tokens[0], "link") == 0) {
4384                 cmd_link(tokens, n_tokens, out, out_size);
4385                 return;
4386         }
4387
4388         if (strcmp(tokens[0], "swq") == 0) {
4389                 cmd_swq(tokens, n_tokens, out, out_size);
4390                 return;
4391         }
4392
4393         if (strcmp(tokens[0], "tmgr") == 0) {
4394                 if ((n_tokens >= 3) &&
4395                         (strcmp(tokens[1], "subport") == 0) &&
4396                         (strcmp(tokens[2], "profile") == 0)) {
4397                         cmd_tmgr_subport_profile(tokens, n_tokens,
4398                                 out, out_size);
4399                         return;
4400                 }
4401
4402                 if ((n_tokens >= 3) &&
4403                         (strcmp(tokens[1], "pipe") == 0) &&
4404                         (strcmp(tokens[2], "profile") == 0)) {
4405                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
4406                         return;
4407                 }
4408
4409                 if ((n_tokens >= 5) &&
4410                         (strcmp(tokens[2], "subport") == 0) &&
4411                         (strcmp(tokens[4], "profile") == 0)) {
4412                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
4413                         return;
4414                 }
4415
4416                 if ((n_tokens >= 5) &&
4417                         (strcmp(tokens[2], "subport") == 0) &&
4418                         (strcmp(tokens[4], "pipe") == 0)) {
4419                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
4420                         return;
4421                 }
4422
4423                 cmd_tmgr(tokens, n_tokens, out, out_size);
4424                 return;
4425         }
4426
4427         if (strcmp(tokens[0], "tap") == 0) {
4428                 cmd_tap(tokens, n_tokens, out, out_size);
4429                 return;
4430         }
4431
4432         if (strcmp(tokens[0], "kni") == 0) {
4433                 cmd_kni(tokens, n_tokens, out, out_size);
4434                 return;
4435         }
4436
4437         if (strcmp(tokens[0], "port") == 0) {
4438                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
4439                 return;
4440         }
4441
4442         if (strcmp(tokens[0], "table") == 0) {
4443                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
4444                 return;
4445         }
4446
4447         if (strcmp(tokens[0], "pipeline") == 0) {
4448                 if ((n_tokens >= 3) &&
4449                         (strcmp(tokens[2], "period") == 0)) {
4450                         cmd_pipeline(tokens, n_tokens, out, out_size);
4451                         return;
4452                 }
4453
4454                 if ((n_tokens >= 5) &&
4455                         (strcmp(tokens[2], "port") == 0) &&
4456                         (strcmp(tokens[3], "in") == 0) &&
4457                         (strcmp(tokens[4], "bsz") == 0)) {
4458                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
4459                         return;
4460                 }
4461
4462                 if ((n_tokens >= 5) &&
4463                         (strcmp(tokens[2], "port") == 0) &&
4464                         (strcmp(tokens[3], "out") == 0) &&
4465                         (strcmp(tokens[4], "bsz") == 0)) {
4466                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
4467                         return;
4468                 }
4469
4470                 if ((n_tokens >= 4) &&
4471                         (strcmp(tokens[2], "table") == 0) &&
4472                         (strcmp(tokens[3], "match") == 0)) {
4473                         cmd_pipeline_table(tokens, n_tokens, out, out_size);
4474                         return;
4475                 }
4476
4477                 if ((n_tokens >= 6) &&
4478                         (strcmp(tokens[2], "port") == 0) &&
4479                         (strcmp(tokens[3], "in") == 0) &&
4480                         (strcmp(tokens[5], "table") == 0)) {
4481                         cmd_pipeline_port_in_table(tokens, n_tokens,
4482                                 out, out_size);
4483                         return;
4484                 }
4485
4486                 if ((n_tokens >= 6) &&
4487                         (strcmp(tokens[2], "port") == 0) &&
4488                         (strcmp(tokens[3], "in") == 0) &&
4489                         (strcmp(tokens[5], "stats") == 0)) {
4490                         cmd_pipeline_port_in_stats(tokens, n_tokens,
4491                                 out, out_size);
4492                         return;
4493                 }
4494
4495                 if ((n_tokens >= 6) &&
4496                         (strcmp(tokens[2], "port") == 0) &&
4497                         (strcmp(tokens[3], "in") == 0) &&
4498                         (strcmp(tokens[5], "enable") == 0)) {
4499                         cmd_pipeline_port_in_enable(tokens, n_tokens,
4500                                 out, out_size);
4501                         return;
4502                 }
4503
4504                 if ((n_tokens >= 6) &&
4505                         (strcmp(tokens[2], "port") == 0) &&
4506                         (strcmp(tokens[3], "in") == 0) &&
4507                         (strcmp(tokens[5], "disable") == 0)) {
4508                         cmd_pipeline_port_in_disable(tokens, n_tokens,
4509                                 out, out_size);
4510                         return;
4511                 }
4512
4513                 if ((n_tokens >= 6) &&
4514                         (strcmp(tokens[2], "port") == 0) &&
4515                         (strcmp(tokens[3], "out") == 0) &&
4516                         (strcmp(tokens[5], "stats") == 0)) {
4517                         cmd_pipeline_port_out_stats(tokens, n_tokens,
4518                                 out, out_size);
4519                         return;
4520                 }
4521
4522                 if ((n_tokens >= 5) &&
4523                         (strcmp(tokens[2], "table") == 0) &&
4524                         (strcmp(tokens[4], "stats") == 0)) {
4525                         cmd_pipeline_table_stats(tokens, n_tokens,
4526                                 out, out_size);
4527                         return;
4528                 }
4529
4530                 if ((n_tokens >= 7) &&
4531                         (strcmp(tokens[2], "table") == 0) &&
4532                         (strcmp(tokens[4], "rule") == 0) &&
4533                         (strcmp(tokens[5], "add") == 0) &&
4534                         (strcmp(tokens[6], "match") == 0)) {
4535                         if ((n_tokens >= 8) &&
4536                                 (strcmp(tokens[7], "default") == 0)) {
4537                                 cmd_pipeline_table_rule_add_default(tokens,
4538                                         n_tokens, out, out_size);
4539                                 return;
4540                         }
4541
4542                         cmd_pipeline_table_rule_add(tokens, n_tokens,
4543                                 out, out_size);
4544                         return;
4545                 }
4546
4547                 if ((n_tokens >= 7) &&
4548                         (strcmp(tokens[2], "table") == 0) &&
4549                         (strcmp(tokens[4], "rule") == 0) &&
4550                         (strcmp(tokens[5], "add") == 0) &&
4551                         (strcmp(tokens[6], "bulk") == 0)) {
4552                         cmd_pipeline_table_rule_add_bulk(tokens,
4553                                 n_tokens, out, out_size);
4554                         return;
4555                 }
4556
4557                 if ((n_tokens >= 7) &&
4558                         (strcmp(tokens[2], "table") == 0) &&
4559                         (strcmp(tokens[4], "rule") == 0) &&
4560                         (strcmp(tokens[5], "delete") == 0) &&
4561                         (strcmp(tokens[6], "match") == 0)) {
4562                         if ((n_tokens >= 8) &&
4563                                 (strcmp(tokens[7], "default") == 0)) {
4564                                 cmd_pipeline_table_rule_delete_default(tokens,
4565                                         n_tokens, out, out_size);
4566                                 return;
4567                                 }
4568
4569                         cmd_pipeline_table_rule_delete(tokens, n_tokens,
4570                                 out, out_size);
4571                         return;
4572                 }
4573
4574                 if ((n_tokens >= 7) &&
4575                         (strcmp(tokens[2], "table") == 0) &&
4576                         (strcmp(tokens[4], "rule") == 0) &&
4577                         (strcmp(tokens[5], "read") == 0) &&
4578                         (strcmp(tokens[6], "stats") == 0)) {
4579                         cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
4580                                 out, out_size);
4581                         return;
4582                 }
4583
4584                 if ((n_tokens >= 8) &&
4585                         (strcmp(tokens[2], "table") == 0) &&
4586                         (strcmp(tokens[4], "meter") == 0) &&
4587                         (strcmp(tokens[5], "profile") == 0) &&
4588                         (strcmp(tokens[7], "add") == 0)) {
4589                         cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
4590                                 out, out_size);
4591                         return;
4592                 }
4593
4594                 if ((n_tokens >= 8) &&
4595                         (strcmp(tokens[2], "table") == 0) &&
4596                         (strcmp(tokens[4], "meter") == 0) &&
4597                         (strcmp(tokens[5], "profile") == 0) &&
4598                         (strcmp(tokens[7], "delete") == 0)) {
4599                         cmd_pipeline_table_meter_profile_delete(tokens,
4600                                 n_tokens, out, out_size);
4601                         return;
4602                 }
4603
4604                 if ((n_tokens >= 7) &&
4605                         (strcmp(tokens[2], "table") == 0) &&
4606                         (strcmp(tokens[4], "rule") == 0) &&
4607                         (strcmp(tokens[5], "read") == 0) &&
4608                         (strcmp(tokens[6], "meter") == 0)) {
4609                         cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
4610                                 out, out_size);
4611                         return;
4612                 }
4613
4614                 if ((n_tokens >= 5) &&
4615                         (strcmp(tokens[2], "table") == 0) &&
4616                         (strcmp(tokens[4], "dscp") == 0)) {
4617                         cmd_pipeline_table_dscp(tokens, n_tokens,
4618                                 out, out_size);
4619                         return;
4620                 }
4621
4622                 if ((n_tokens >= 7) &&
4623                         (strcmp(tokens[2], "table") == 0) &&
4624                         (strcmp(tokens[4], "rule") == 0) &&
4625                         (strcmp(tokens[5], "read") == 0) &&
4626                         (strcmp(tokens[6], "ttl") == 0)) {
4627                         cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
4628                                 out, out_size);
4629                         return;
4630                 }
4631         }
4632
4633         if (strcmp(tokens[0], "thread") == 0) {
4634                 if ((n_tokens >= 5) &&
4635                         (strcmp(tokens[4], "enable") == 0)) {
4636                         cmd_thread_pipeline_enable(tokens, n_tokens,
4637                                 out, out_size);
4638                         return;
4639                 }
4640
4641                 if ((n_tokens >= 5) &&
4642                         (strcmp(tokens[4], "disable") == 0)) {
4643                         cmd_thread_pipeline_disable(tokens, n_tokens,
4644                                 out, out_size);
4645                         return;
4646                 }
4647         }
4648
4649         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
4650 }
4651
4652 int
4653 cli_script_process(const char *file_name,
4654         size_t msg_in_len_max,
4655         size_t msg_out_len_max)
4656 {
4657         char *msg_in = NULL, *msg_out = NULL;
4658         FILE *f = NULL;
4659
4660         /* Check input arguments */
4661         if ((file_name == NULL) ||
4662                 (strlen(file_name) == 0) ||
4663                 (msg_in_len_max == 0) ||
4664                 (msg_out_len_max == 0))
4665                 return -EINVAL;
4666
4667         msg_in = malloc(msg_in_len_max + 1);
4668         msg_out = malloc(msg_out_len_max + 1);
4669         if ((msg_in == NULL) ||
4670                 (msg_out == NULL)) {
4671                 free(msg_out);
4672                 free(msg_in);
4673                 return -ENOMEM;
4674         }
4675
4676         /* Open input file */
4677         f = fopen(file_name, "r");
4678         if (f == NULL) {
4679                 free(msg_out);
4680                 free(msg_in);
4681                 return -EIO;
4682         }
4683
4684         /* Read file */
4685         for ( ; ; ) {
4686                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
4687                         break;
4688
4689                 printf("%s", msg_in);
4690                 msg_out[0] = 0;
4691
4692                 cli_process(msg_in,
4693                         msg_out,
4694                         msg_out_len_max);
4695
4696                 if (strlen(msg_out))
4697                         printf("%s", msg_out);
4698         }
4699
4700         /* Close file */
4701         fclose(f);
4702         free(msg_out);
4703         free(msg_in);
4704         return 0;
4705 }
4706
4707 static int
4708 cli_rule_file_process(const char *file_name,
4709         size_t line_len_max,
4710         struct table_rule_match *m,
4711         struct table_rule_action *a,
4712         uint32_t *n_rules,
4713         uint32_t *line_number,
4714         char *out,
4715         size_t out_size)
4716 {
4717         FILE *f = NULL;
4718         char *line = NULL;
4719         uint32_t rule_id, line_id;
4720         int status = 0;
4721
4722         /* Check input arguments */
4723         if ((file_name == NULL) ||
4724                 (strlen(file_name) == 0) ||
4725                 (line_len_max == 0)) {
4726                 *line_number = 0;
4727                 return -EINVAL;
4728         }
4729
4730         /* Memory allocation */
4731         line = malloc(line_len_max + 1);
4732         if (line == NULL) {
4733                 *line_number = 0;
4734                 return -ENOMEM;
4735         }
4736
4737         /* Open file */
4738         f = fopen(file_name, "r");
4739         if (f == NULL) {
4740                 *line_number = 0;
4741                 free(line);
4742                 return -EIO;
4743         }
4744
4745         /* Read file */
4746         for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
4747                 char *tokens[CMD_MAX_TOKENS];
4748                 uint32_t n_tokens, n_tokens_parsed, t0;
4749
4750                 /* Read next line from file. */
4751                 if (fgets(line, line_len_max + 1, f) == NULL)
4752                         break;
4753
4754                 /* Comment. */
4755                 if (is_comment(line))
4756                         continue;
4757
4758                 /* Parse line. */
4759                 n_tokens = RTE_DIM(tokens);
4760                 status = parse_tokenize_string(line, tokens, &n_tokens);
4761                 if (status) {
4762                         status = -EINVAL;
4763                         break;
4764                 }
4765
4766                 /* Empty line. */
4767                 if (n_tokens == 0)
4768                         continue;
4769                 t0 = 0;
4770
4771                 /* Rule match. */
4772                 n_tokens_parsed = parse_match(tokens + t0,
4773                         n_tokens - t0,
4774                         out,
4775                         out_size,
4776                         &m[rule_id]);
4777                 if (n_tokens_parsed == 0) {
4778                         status = -EINVAL;
4779                         break;
4780                 }
4781                 t0 += n_tokens_parsed;
4782
4783                 /* Rule action. */
4784                 n_tokens_parsed = parse_table_action(tokens + t0,
4785                         n_tokens - t0,
4786                         out,
4787                         out_size,
4788                         &a[rule_id]);
4789                 if (n_tokens_parsed == 0) {
4790                         status = -EINVAL;
4791                         break;
4792                 }
4793                 t0 += n_tokens_parsed;
4794
4795                 /* Line completed. */
4796                 if (t0 < n_tokens) {
4797                         status = -EINVAL;
4798                         break;
4799                 }
4800
4801                 /* Increment rule count */
4802                 rule_id++;
4803         }
4804
4805         /* Close file */
4806         fclose(f);
4807
4808         /* Memory free */
4809         free(line);
4810
4811         *n_rules = rule_id;
4812         *line_number = line_id;
4813         return status;
4814 }