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