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