2f30a6d01d06d46bfe18d1731dfcbba22c0e1a72
[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                 if (n_tokens < t0 + 1) {
1897                         snprintf(out, out_size, MSG_ARG_MISMATCH,
1898                                 "pipeline table stub");
1899                         return;
1900                 }
1901
1902                 p.match_type = TABLE_STUB;
1903
1904                 t0 += 1;
1905         } else {
1906                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1907                 return;
1908         }
1909
1910         p.action_profile_name = NULL;
1911         if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1912                 if (n_tokens < t0 + 2) {
1913                         snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1914                         return;
1915                 }
1916
1917                 p.action_profile_name = tokens[t0 + 1];
1918
1919                 t0 += 2;
1920         }
1921
1922         if (n_tokens > t0) {
1923                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1924                 return;
1925         }
1926
1927         status = pipeline_table_create(pipeline_name, &p);
1928         if (status) {
1929                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1930                 return;
1931         }
1932 }
1933
1934 /**
1935  * pipeline <pipeline_name> port in <port_id> table <table_id>
1936  */
1937 static void
1938 cmd_pipeline_port_in_table(char **tokens,
1939         uint32_t n_tokens,
1940         char *out,
1941         size_t out_size)
1942 {
1943         char *pipeline_name;
1944         uint32_t port_id, table_id;
1945         int status;
1946
1947         if (n_tokens != 7) {
1948                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1949                 return;
1950         }
1951
1952         pipeline_name = tokens[1];
1953
1954         if (strcmp(tokens[2], "port") != 0) {
1955                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1956                 return;
1957         }
1958
1959         if (strcmp(tokens[3], "in") != 0) {
1960                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1961                 return;
1962         }
1963
1964         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
1965                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1966                 return;
1967         }
1968
1969         if (strcmp(tokens[5], "table") != 0) {
1970                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1971                 return;
1972         }
1973
1974         if (parser_read_uint32(&table_id, tokens[6]) != 0) {
1975                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
1976                 return;
1977         }
1978
1979         status = pipeline_port_in_connect_to_table(pipeline_name,
1980                 port_id,
1981                 table_id);
1982         if (status) {
1983                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1984                 return;
1985         }
1986 }
1987
1988 /**
1989  * pipeline <pipeline_name> port in <port_id> stats read [clear]
1990  */
1991
1992 #define MSG_PIPELINE_PORT_IN_STATS                         \
1993         "Pkts in: %" PRIu64 "\n"                           \
1994         "Pkts dropped by AH: %" PRIu64 "\n"                \
1995         "Pkts dropped by other: %" PRIu64 "\n"
1996
1997 static void
1998 cmd_pipeline_port_in_stats(char **tokens,
1999         uint32_t n_tokens,
2000         char *out,
2001         size_t out_size)
2002 {
2003         struct rte_pipeline_port_in_stats stats;
2004         char *pipeline_name;
2005         uint32_t port_id;
2006         int clear, status;
2007
2008         if ((n_tokens != 7) && (n_tokens != 8)) {
2009                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2010                 return;
2011         }
2012
2013         pipeline_name = tokens[1];
2014
2015         if (strcmp(tokens[2], "port") != 0) {
2016                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2017                 return;
2018         }
2019
2020         if (strcmp(tokens[3], "in") != 0) {
2021                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2022                 return;
2023         }
2024
2025         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2026                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2027                 return;
2028         }
2029
2030         if (strcmp(tokens[5], "stats") != 0) {
2031                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2032                 return;
2033         }
2034
2035         if (strcmp(tokens[6], "read") != 0) {
2036                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2037                 return;
2038         }
2039
2040         clear = 0;
2041         if (n_tokens == 8) {
2042                 if (strcmp(tokens[7], "clear") != 0) {
2043                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2044                         return;
2045                 }
2046
2047                 clear = 1;
2048         }
2049
2050         status = pipeline_port_in_stats_read(pipeline_name,
2051                 port_id,
2052                 &stats,
2053                 clear);
2054         if (status) {
2055                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2056                 return;
2057         }
2058
2059         snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
2060                 stats.stats.n_pkts_in,
2061                 stats.n_pkts_dropped_by_ah,
2062                 stats.stats.n_pkts_drop);
2063 }
2064
2065 /**
2066  * pipeline <pipeline_name> port in <port_id> enable
2067  */
2068 static void
2069 cmd_pipeline_port_in_enable(char **tokens,
2070         uint32_t n_tokens,
2071         char *out,
2072         size_t out_size)
2073 {
2074         char *pipeline_name;
2075         uint32_t port_id;
2076         int status;
2077
2078         if (n_tokens != 6) {
2079                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2080                 return;
2081         }
2082
2083         pipeline_name = tokens[1];
2084
2085         if (strcmp(tokens[2], "port") != 0) {
2086                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2087                 return;
2088         }
2089
2090         if (strcmp(tokens[3], "in") != 0) {
2091                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2092                 return;
2093         }
2094
2095         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2096                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2097                 return;
2098         }
2099
2100         if (strcmp(tokens[5], "enable") != 0) {
2101                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2102                 return;
2103         }
2104
2105         status = pipeline_port_in_enable(pipeline_name, port_id);
2106         if (status) {
2107                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2108                 return;
2109         }
2110 }
2111
2112 /**
2113  * pipeline <pipeline_name> port in <port_id> disable
2114  */
2115 static void
2116 cmd_pipeline_port_in_disable(char **tokens,
2117         uint32_t n_tokens,
2118         char *out,
2119         size_t out_size)
2120 {
2121         char *pipeline_name;
2122         uint32_t port_id;
2123         int status;
2124
2125         if (n_tokens != 6) {
2126                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2127                 return;
2128         }
2129
2130         pipeline_name = tokens[1];
2131
2132         if (strcmp(tokens[2], "port") != 0) {
2133                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2134                 return;
2135         }
2136
2137         if (strcmp(tokens[3], "in") != 0) {
2138                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2139                 return;
2140         }
2141
2142         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2143                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2144                 return;
2145         }
2146
2147         if (strcmp(tokens[5], "disable") != 0) {
2148                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2149                 return;
2150         }
2151
2152         status = pipeline_port_in_disable(pipeline_name, port_id);
2153         if (status) {
2154                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2155                 return;
2156         }
2157 }
2158
2159 /**
2160  * pipeline <pipeline_name> port out <port_id> stats read [clear]
2161  */
2162 #define MSG_PIPELINE_PORT_OUT_STATS                        \
2163         "Pkts in: %" PRIu64 "\n"                           \
2164         "Pkts dropped by AH: %" PRIu64 "\n"                \
2165         "Pkts dropped by other: %" PRIu64 "\n"
2166
2167 static void
2168 cmd_pipeline_port_out_stats(char **tokens,
2169         uint32_t n_tokens,
2170         char *out,
2171         size_t out_size)
2172 {
2173         struct rte_pipeline_port_out_stats stats;
2174         char *pipeline_name;
2175         uint32_t port_id;
2176         int clear, status;
2177
2178         if ((n_tokens != 7) && (n_tokens != 8)) {
2179                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2180                 return;
2181         }
2182
2183         pipeline_name = tokens[1];
2184
2185         if (strcmp(tokens[2], "port") != 0) {
2186                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2187                 return;
2188         }
2189
2190         if (strcmp(tokens[3], "out") != 0) {
2191                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2192                 return;
2193         }
2194
2195         if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2196                 snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2197                 return;
2198         }
2199
2200         if (strcmp(tokens[5], "stats") != 0) {
2201                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2202                 return;
2203         }
2204
2205         if (strcmp(tokens[6], "read") != 0) {
2206                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2207                 return;
2208         }
2209
2210         clear = 0;
2211         if (n_tokens == 8) {
2212                 if (strcmp(tokens[7], "clear") != 0) {
2213                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2214                         return;
2215                 }
2216
2217                 clear = 1;
2218         }
2219
2220         status = pipeline_port_out_stats_read(pipeline_name,
2221                 port_id,
2222                 &stats,
2223                 clear);
2224         if (status) {
2225                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2226                 return;
2227         }
2228
2229         snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
2230                 stats.stats.n_pkts_in,
2231                 stats.n_pkts_dropped_by_ah,
2232                 stats.stats.n_pkts_drop);
2233 }
2234
2235 /**
2236  * pipeline <pipeline_name> table <table_id> stats read [clear]
2237  */
2238 #define MSG_PIPELINE_TABLE_STATS                                     \
2239         "Pkts in: %" PRIu64 "\n"                                     \
2240         "Pkts in with lookup miss: %" PRIu64 "\n"                    \
2241         "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
2242         "Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
2243         "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
2244         "Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
2245
2246 static void
2247 cmd_pipeline_table_stats(char **tokens,
2248         uint32_t n_tokens,
2249         char *out,
2250         size_t out_size)
2251 {
2252         struct rte_pipeline_table_stats stats;
2253         char *pipeline_name;
2254         uint32_t table_id;
2255         int clear, status;
2256
2257         if ((n_tokens != 6) && (n_tokens != 7)) {
2258                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2259                 return;
2260         }
2261
2262         pipeline_name = tokens[1];
2263
2264         if (strcmp(tokens[2], "table") != 0) {
2265                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2266                 return;
2267         }
2268
2269         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
2270                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2271                 return;
2272         }
2273
2274         if (strcmp(tokens[4], "stats") != 0) {
2275                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2276                 return;
2277         }
2278
2279         if (strcmp(tokens[5], "read") != 0) {
2280                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2281                 return;
2282         }
2283
2284         clear = 0;
2285         if (n_tokens == 7) {
2286                 if (strcmp(tokens[6], "clear") != 0) {
2287                         snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2288                         return;
2289                 }
2290
2291                 clear = 1;
2292         }
2293
2294         status = pipeline_table_stats_read(pipeline_name,
2295                 table_id,
2296                 &stats,
2297                 clear);
2298         if (status) {
2299                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2300                 return;
2301         }
2302
2303         snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
2304                 stats.stats.n_pkts_in,
2305                 stats.stats.n_pkts_lookup_miss,
2306                 stats.n_pkts_dropped_by_lkp_hit_ah,
2307                 stats.n_pkts_dropped_lkp_hit,
2308                 stats.n_pkts_dropped_by_lkp_miss_ah,
2309                 stats.n_pkts_dropped_lkp_miss);
2310 }
2311
2312 /**
2313  * <match> ::=
2314  *
2315  * match
2316  *    acl
2317  *       priority <priority>
2318  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
2319  *       <sp0> <sp1> <dp0> <dp1> <proto>
2320  *    | array <pos>
2321  *    | hash
2322  *       raw <key>
2323  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2324  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2325  *       | ipv4_addr <addr>
2326  *       | ipv6_addr <addr>
2327  *       | qinq <svlan> <cvlan>
2328  *    | lpm
2329  *       ipv4 | ipv6 <addr> <depth>
2330  */
2331 struct pkt_key_qinq {
2332         uint16_t ethertype_svlan;
2333         uint16_t svlan;
2334         uint16_t ethertype_cvlan;
2335         uint16_t cvlan;
2336 } __attribute__((__packed__));
2337
2338 struct pkt_key_ipv4_5tuple {
2339         uint8_t time_to_live;
2340         uint8_t proto;
2341         uint16_t hdr_checksum;
2342         uint32_t sa;
2343         uint32_t da;
2344         uint16_t sp;
2345         uint16_t dp;
2346 } __attribute__((__packed__));
2347
2348 struct pkt_key_ipv6_5tuple {
2349         uint16_t payload_length;
2350         uint8_t proto;
2351         uint8_t hop_limit;
2352         uint8_t sa[16];
2353         uint8_t da[16];
2354         uint16_t sp;
2355         uint16_t dp;
2356 } __attribute__((__packed__));
2357
2358 struct pkt_key_ipv4_addr {
2359         uint32_t addr;
2360 } __attribute__((__packed__));
2361
2362 struct pkt_key_ipv6_addr {
2363         uint8_t addr[16];
2364 } __attribute__((__packed__));
2365
2366 static uint32_t
2367 parse_match(char **tokens,
2368         uint32_t n_tokens,
2369         char *out,
2370         size_t out_size,
2371         struct table_rule_match *m)
2372 {
2373         memset(m, 0, sizeof(*m));
2374
2375         if (n_tokens < 2)
2376                 return 0;
2377
2378         if (strcmp(tokens[0], "match") != 0) {
2379                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2380                 return 0;
2381         }
2382
2383         if (strcmp(tokens[1], "acl") == 0) {
2384                 if (n_tokens < 14) {
2385                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2386                         return 0;
2387                 }
2388
2389                 m->match_type = TABLE_ACL;
2390
2391                 if (strcmp(tokens[2], "priority") != 0) {
2392                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
2393                         return 0;
2394                 }
2395
2396                 if (parser_read_uint32(&m->match.acl.priority,
2397                         tokens[3]) != 0) {
2398                         snprintf(out, out_size, MSG_ARG_INVALID, "priority");
2399                         return 0;
2400                 }
2401
2402                 if (strcmp(tokens[4], "ipv4") == 0) {
2403                         struct in_addr saddr, daddr;
2404
2405                         m->match.acl.ip_version = 1;
2406
2407                         if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
2408                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2409                                 return 0;
2410                         }
2411                         m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
2412
2413                         if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
2414                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2415                                 return 0;
2416                         }
2417                         m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
2418                 } else if (strcmp(tokens[4], "ipv6") == 0) {
2419                         struct in6_addr saddr, daddr;
2420
2421                         m->match.acl.ip_version = 0;
2422
2423                         if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
2424                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2425                                 return 0;
2426                         }
2427                         memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2428
2429                         if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2430                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2431                                 return 0;
2432                         }
2433                         memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
2434                 } else {
2435                         snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2436                                 "ipv4 or ipv6");
2437                         return 0;
2438                 }
2439
2440                 if (parser_read_uint32(&m->match.acl.sa_depth,
2441                         tokens[6]) != 0) {
2442                         snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
2443                         return 0;
2444                 }
2445
2446                 if (parser_read_uint32(&m->match.acl.da_depth,
2447                         tokens[8]) != 0) {
2448                         snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
2449                         return 0;
2450                 }
2451
2452                 if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
2453                         snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
2454                         return 0;
2455                 }
2456
2457                 if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
2458                         snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
2459                         return 0;
2460                 }
2461
2462                 if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
2463                         snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
2464                         return 0;
2465                 }
2466
2467                 if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
2468                         snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
2469                         return 0;
2470                 }
2471
2472                 if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
2473                         snprintf(out, out_size, MSG_ARG_INVALID, "proto");
2474                         return 0;
2475                 }
2476
2477                 m->match.acl.proto_mask = 0xff;
2478
2479                 return 14;
2480         } /* acl */
2481
2482         if (strcmp(tokens[1], "array") == 0) {
2483                 if (n_tokens < 3) {
2484                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2485                         return 0;
2486                 }
2487
2488                 m->match_type = TABLE_ARRAY;
2489
2490                 if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
2491                         snprintf(out, out_size, MSG_ARG_INVALID, "pos");
2492                         return 0;
2493                 }
2494
2495                 return 3;
2496         } /* array */
2497
2498         if (strcmp(tokens[1], "hash") == 0) {
2499                 if (n_tokens < 3) {
2500                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2501                         return 0;
2502                 }
2503
2504                 m->match_type = TABLE_HASH;
2505
2506                 if (strcmp(tokens[2], "raw") == 0) {
2507                         uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
2508
2509                         if (n_tokens < 4) {
2510                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2511                                         tokens[0]);
2512                                 return 0;
2513                         }
2514
2515                         if (parse_hex_string(tokens[3],
2516                                 m->match.hash.key, &key_size) != 0) {
2517                                 snprintf(out, out_size, MSG_ARG_INVALID, "key");
2518                                 return 0;
2519                         }
2520
2521                         return 4;
2522                 } /* hash raw */
2523
2524                 if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
2525                         struct pkt_key_ipv4_5tuple *ipv4 =
2526                                 (struct pkt_key_ipv4_5tuple *) m->match.hash.key;
2527                         struct in_addr saddr, daddr;
2528                         uint16_t sp, dp;
2529                         uint8_t proto;
2530
2531                         if (n_tokens < 8) {
2532                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2533                                         tokens[0]);
2534                                 return 0;
2535                         }
2536
2537                         if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
2538                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2539                                 return 0;
2540                         }
2541
2542                         if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
2543                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2544                                 return 0;
2545                         }
2546
2547                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2548                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2549                                 return 0;
2550                         }
2551
2552                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2553                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2554                                 return 0;
2555                         }
2556
2557                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2558                                 snprintf(out, out_size, MSG_ARG_INVALID,
2559                                         "proto");
2560                                 return 0;
2561                         }
2562
2563                         ipv4->sa = saddr.s_addr;
2564                         ipv4->da = daddr.s_addr;
2565                         ipv4->sp = rte_cpu_to_be_16(sp);
2566                         ipv4->dp = rte_cpu_to_be_16(dp);
2567                         ipv4->proto = proto;
2568
2569                         return 8;
2570                 } /* hash ipv4_5tuple */
2571
2572                 if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
2573                         struct pkt_key_ipv6_5tuple *ipv6 =
2574                                 (struct pkt_key_ipv6_5tuple *) m->match.hash.key;
2575                         struct in6_addr saddr, daddr;
2576                         uint16_t sp, dp;
2577                         uint8_t proto;
2578
2579                         if (n_tokens < 8) {
2580                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2581                                         tokens[0]);
2582                                 return 0;
2583                         }
2584
2585                         if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
2586                                 snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2587                                 return 0;
2588                         }
2589
2590                         if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
2591                                 snprintf(out, out_size, MSG_ARG_INVALID, "da");
2592                                 return 0;
2593                         }
2594
2595                         if (parser_read_uint16(&sp, tokens[5]) != 0) {
2596                                 snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2597                                 return 0;
2598                         }
2599
2600                         if (parser_read_uint16(&dp, tokens[6]) != 0) {
2601                                 snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2602                                 return 0;
2603                         }
2604
2605                         if (parser_read_uint8(&proto, tokens[7]) != 0) {
2606                                 snprintf(out, out_size, MSG_ARG_INVALID,
2607                                         "proto");
2608                                 return 0;
2609                         }
2610
2611                         memcpy(ipv6->sa, saddr.s6_addr, 16);
2612                         memcpy(ipv6->da, daddr.s6_addr, 16);
2613                         ipv6->sp = rte_cpu_to_be_16(sp);
2614                         ipv6->dp = rte_cpu_to_be_16(dp);
2615                         ipv6->proto = proto;
2616
2617                         return 8;
2618                 } /* hash ipv6_5tuple */
2619
2620                 if (strcmp(tokens[2], "ipv4_addr") == 0) {
2621                         struct pkt_key_ipv4_addr *ipv4_addr =
2622                                 (struct pkt_key_ipv4_addr *) m->match.hash.key;
2623                         struct in_addr addr;
2624
2625                         if (n_tokens < 4) {
2626                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2627                                         tokens[0]);
2628                                 return 0;
2629                         }
2630
2631                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2632                                 snprintf(out, out_size, MSG_ARG_INVALID,
2633                                         "addr");
2634                                 return 0;
2635                         }
2636
2637                         ipv4_addr->addr = addr.s_addr;
2638
2639                         return 4;
2640                 } /* hash ipv4_addr */
2641
2642                 if (strcmp(tokens[2], "ipv6_addr") == 0) {
2643                         struct pkt_key_ipv6_addr *ipv6_addr =
2644                                 (struct pkt_key_ipv6_addr *) m->match.hash.key;
2645                         struct in6_addr addr;
2646
2647                         if (n_tokens < 4) {
2648                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2649                                         tokens[0]);
2650                                 return 0;
2651                         }
2652
2653                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2654                                 snprintf(out, out_size, MSG_ARG_INVALID,
2655                                         "addr");
2656                                 return 0;
2657                         }
2658
2659                         memcpy(ipv6_addr->addr, addr.s6_addr, 16);
2660
2661                         return 4;
2662                 } /* hash ipv6_5tuple */
2663
2664                 if (strcmp(tokens[2], "qinq") == 0) {
2665                         struct pkt_key_qinq *qinq =
2666                                 (struct pkt_key_qinq *) m->match.hash.key;
2667                         uint16_t svlan, cvlan;
2668
2669                         if (n_tokens < 5) {
2670                                 snprintf(out, out_size, MSG_ARG_MISMATCH,
2671                                         tokens[0]);
2672                                 return 0;
2673                         }
2674
2675                         if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
2676                                 (svlan > 0xFFF)) {
2677                                 snprintf(out, out_size, MSG_ARG_INVALID,
2678                                         "svlan");
2679                                 return 0;
2680                         }
2681
2682                         if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
2683                                 (cvlan > 0xFFF)) {
2684                                 snprintf(out, out_size, MSG_ARG_INVALID,
2685                                         "cvlan");
2686                                 return 0;
2687                         }
2688
2689                         qinq->svlan = rte_cpu_to_be_16(svlan);
2690                         qinq->cvlan = rte_cpu_to_be_16(cvlan);
2691
2692                         return 5;
2693                 } /* hash qinq */
2694
2695                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2696                 return 0;
2697         } /* hash */
2698
2699         if (strcmp(tokens[1], "lpm") == 0) {
2700                 if (n_tokens < 5) {
2701                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2702                         return 0;
2703                 }
2704
2705                 m->match_type = TABLE_LPM;
2706
2707                 if (strcmp(tokens[2], "ipv4") == 0) {
2708                         struct in_addr addr;
2709
2710                         m->match.lpm.ip_version = 1;
2711
2712                         if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2713                                 snprintf(out, out_size, MSG_ARG_INVALID,
2714                                         "addr");
2715                                 return 0;
2716                         }
2717
2718                         m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
2719                 } else if (strcmp(tokens[2], "ipv6") == 0) {
2720                         struct in6_addr addr;
2721
2722                         m->match.lpm.ip_version = 0;
2723
2724                         if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2725                                 snprintf(out, out_size, MSG_ARG_INVALID,
2726                                         "addr");
2727                                 return 0;
2728                         }
2729
2730                         memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
2731                 } else {
2732                         snprintf(out, out_size, MSG_ARG_MISMATCH,
2733                                 "ipv4 or ipv6");
2734                         return 0;
2735                 }
2736
2737                 if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
2738                         snprintf(out, out_size, MSG_ARG_INVALID, "depth");
2739                         return 0;
2740                 }
2741
2742                 return 5;
2743         } /* lpm */
2744
2745         snprintf(out, out_size, MSG_ARG_MISMATCH,
2746                 "acl or array or hash or lpm");
2747         return 0;
2748 }
2749
2750 /**
2751  * table_action ::=
2752  *
2753  * action
2754  *    fwd
2755  *       drop
2756  *       | port <port_id>
2757  *       | meta
2758  *       | table <table_id>
2759  *    [balance <out0> ... <out7>]
2760  *    [meter
2761  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2762  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2763  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
2764  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
2765  *    [tm subport <subport_id> pipe <pipe_id>]
2766  *    [encap
2767  *       ether <da> <sa>
2768  *       | vlan <da> <sa> <pcp> <dei> <vid>
2769  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
2770  *       | mpls unicast | multicast
2771  *          <da> <sa>
2772  *          label0 <label> <tc> <ttl>
2773  *          [label1 <label> <tc> <ttl>
2774  *          [label2 <label> <tc> <ttl>
2775  *          [label3 <label> <tc> <ttl>]]]
2776  *       | pppoe <da> <sa> <session_id>]
2777  *    [nat ipv4 | ipv6 <addr> <port>]
2778  *    [ttl dec | keep]
2779  *    [stats]
2780  *    [time]
2781  *
2782  * where:
2783  *    <pa> ::= g | y | r | drop
2784  */
2785 static uint32_t
2786 parse_table_action_fwd(char **tokens,
2787         uint32_t n_tokens,
2788         struct table_rule_action *a)
2789 {
2790         if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
2791                 return 0;
2792
2793         tokens++;
2794         n_tokens--;
2795
2796         if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
2797                 a->fwd.action = RTE_PIPELINE_ACTION_DROP;
2798                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2799                 return 1 + 1;
2800         }
2801
2802         if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
2803                 uint32_t id;
2804
2805                 if ((n_tokens < 2) ||
2806                         parser_read_uint32(&id, tokens[1]))
2807                         return 0;
2808
2809                 a->fwd.action = RTE_PIPELINE_ACTION_PORT;
2810                 a->fwd.id = id;
2811                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2812                 return 1 + 2;
2813         }
2814
2815         if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
2816                 a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
2817                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2818                 return 1 + 1;
2819         }
2820
2821         if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
2822                 uint32_t id;
2823
2824                 if ((n_tokens < 2) ||
2825                         parser_read_uint32(&id, tokens[1]))
2826                         return 0;
2827
2828                 a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
2829                 a->fwd.id = id;
2830                 a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
2831                 return 1 + 2;
2832         }
2833
2834         return 0;
2835 }
2836
2837 static uint32_t
2838 parse_table_action_balance(char **tokens,
2839         uint32_t n_tokens,
2840         struct table_rule_action *a)
2841 {
2842         uint32_t i;
2843
2844         if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0))
2845                 return 0;
2846
2847         tokens++;
2848         n_tokens--;
2849
2850         if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE)
2851                 return 0;
2852
2853         for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++)
2854                 if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
2855                         return 0;
2856
2857         a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
2858         return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE;
2859
2860 }
2861
2862 static int
2863 parse_policer_action(char *token, enum rte_table_action_policer *a)
2864 {
2865         if (strcmp(token, "g") == 0) {
2866                 *a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
2867                 return 0;
2868         }
2869
2870         if (strcmp(token, "y") == 0) {
2871                 *a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
2872                 return 0;
2873         }
2874
2875         if (strcmp(token, "r") == 0) {
2876                 *a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
2877                 return 0;
2878         }
2879
2880         if (strcmp(token, "drop") == 0) {
2881                 *a = RTE_TABLE_ACTION_POLICER_DROP;
2882                 return 0;
2883         }
2884
2885         return -1;
2886 }
2887
2888 static uint32_t
2889 parse_table_action_meter_tc(char **tokens,
2890         uint32_t n_tokens,
2891         struct rte_table_action_mtr_tc_params *mtr)
2892 {
2893         if ((n_tokens < 9) ||
2894                 strcmp(tokens[0], "meter") ||
2895                 parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
2896                 strcmp(tokens[2], "policer") ||
2897                 strcmp(tokens[3], "g") ||
2898                 parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
2899                 strcmp(tokens[5], "y") ||
2900                 parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
2901                 strcmp(tokens[7], "r") ||
2902                 parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
2903                 return 0;
2904
2905         return 9;
2906 }
2907
2908 static uint32_t
2909 parse_table_action_meter(char **tokens,
2910         uint32_t n_tokens,
2911         struct table_rule_action *a)
2912 {
2913         if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
2914                 return 0;
2915
2916         tokens++;
2917         n_tokens--;
2918
2919         if ((n_tokens < 10) ||
2920                 strcmp(tokens[0], "tc0") ||
2921                 (parse_table_action_meter_tc(tokens + 1,
2922                         n_tokens - 1,
2923                         &a->mtr.mtr[0]) == 0))
2924                 return 0;
2925
2926         tokens += 10;
2927         n_tokens -= 10;
2928
2929         if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
2930                 a->mtr.tc_mask = 1;
2931                 a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2932                 return 1 + 10;
2933         }
2934
2935         if ((n_tokens < 30) ||
2936                 (parse_table_action_meter_tc(tokens + 1,
2937                         n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
2938                 strcmp(tokens[10], "tc2") ||
2939                 (parse_table_action_meter_tc(tokens + 11,
2940                         n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
2941                 strcmp(tokens[20], "tc3") ||
2942                 (parse_table_action_meter_tc(tokens + 21,
2943                         n_tokens - 21, &a->mtr.mtr[3]) == 0))
2944                 return 0;
2945
2946         a->mtr.tc_mask = 0xF;
2947         a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
2948         return 1 + 10 + 3 * 10;
2949 }
2950
2951 static uint32_t
2952 parse_table_action_tm(char **tokens,
2953         uint32_t n_tokens,
2954         struct table_rule_action *a)
2955 {
2956         uint32_t subport_id, pipe_id;
2957
2958         if ((n_tokens < 5) ||
2959                 strcmp(tokens[0], "tm") ||
2960                 strcmp(tokens[1], "subport") ||
2961                 parser_read_uint32(&subport_id, tokens[2]) ||
2962                 strcmp(tokens[3], "pipe") ||
2963                 parser_read_uint32(&pipe_id, tokens[4]))
2964                 return 0;
2965
2966         a->tm.subport_id = subport_id;
2967         a->tm.pipe_id = pipe_id;
2968         a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
2969         return 5;
2970 }
2971
2972 static uint32_t
2973 parse_table_action_encap(char **tokens,
2974         uint32_t n_tokens,
2975         struct table_rule_action *a)
2976 {
2977         if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
2978                 return 0;
2979
2980         tokens++;
2981         n_tokens--;
2982
2983         /* ether */
2984         if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
2985                 if ((n_tokens < 3) ||
2986                         parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
2987                         parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
2988                         return 0;
2989
2990                 a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
2991                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
2992                 return 1 + 3;
2993         }
2994
2995         /* vlan */
2996         if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
2997                 uint32_t pcp, dei, vid;
2998
2999                 if ((n_tokens < 6) ||
3000                         parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
3001                         parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
3002                         parser_read_uint32(&pcp, tokens[3]) ||
3003                         (pcp > 0x7) ||
3004                         parser_read_uint32(&dei, tokens[4]) ||
3005                         (dei > 0x1) ||
3006                         parser_read_uint32(&vid, tokens[5]) ||
3007                         (vid > 0xFFF))
3008                         return 0;
3009
3010                 a->encap.vlan.vlan.pcp = pcp & 0x7;
3011                 a->encap.vlan.vlan.dei = dei & 0x1;
3012                 a->encap.vlan.vlan.vid = vid & 0xFFF;
3013                 a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
3014                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3015                 return 1 + 6;
3016         }
3017
3018         /* qinq */
3019         if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
3020                 uint32_t svlan_pcp, svlan_dei, svlan_vid;
3021                 uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3022
3023                 if ((n_tokens < 9) ||
3024                         parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
3025                         parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
3026                         parser_read_uint32(&svlan_pcp, tokens[3]) ||
3027                         (svlan_pcp > 0x7) ||
3028                         parser_read_uint32(&svlan_dei, tokens[4]) ||
3029                         (svlan_dei > 0x1) ||
3030                         parser_read_uint32(&svlan_vid, tokens[5]) ||
3031                         (svlan_vid > 0xFFF) ||
3032                         parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3033                         (cvlan_pcp > 0x7) ||
3034                         parser_read_uint32(&cvlan_dei, tokens[7]) ||
3035                         (cvlan_dei > 0x1) ||
3036                         parser_read_uint32(&cvlan_vid, tokens[8]) ||
3037                         (cvlan_vid > 0xFFF))
3038                         return 0;
3039
3040                 a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
3041                 a->encap.qinq.svlan.dei = svlan_dei & 0x1;
3042                 a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
3043                 a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
3044                 a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
3045                 a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
3046                 a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
3047                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3048                 return 1 + 9;
3049         }
3050
3051         /* mpls */
3052         if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
3053                 uint32_t label, tc, ttl;
3054
3055                 if (n_tokens < 8)
3056                         return 0;
3057
3058                 if (strcmp(tokens[1], "unicast") == 0)
3059                         a->encap.mpls.unicast = 1;
3060                 else if (strcmp(tokens[1], "multicast") == 0)
3061                         a->encap.mpls.unicast = 0;
3062                 else
3063                         return 0;
3064
3065                 if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
3066                         parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
3067                         strcmp(tokens[4], "label0") ||
3068                         parser_read_uint32(&label, tokens[5]) ||
3069                         (label > 0xFFFFF) ||
3070                         parser_read_uint32(&tc, tokens[6]) ||
3071                         (tc > 0x7) ||
3072                         parser_read_uint32(&ttl, tokens[7]) ||
3073                         (ttl > 0x3F))
3074                         return 0;
3075
3076                 a->encap.mpls.mpls[0].label = label;
3077                 a->encap.mpls.mpls[0].tc = tc;
3078                 a->encap.mpls.mpls[0].ttl = ttl;
3079
3080                 tokens += 8;
3081                 n_tokens -= 8;
3082
3083                 if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
3084                         a->encap.mpls.mpls_count = 1;
3085                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3086                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3087                         return 1 + 8;
3088                 }
3089
3090                 if ((n_tokens < 4) ||
3091                         parser_read_uint32(&label, tokens[1]) ||
3092                         (label > 0xFFFFF) ||
3093                         parser_read_uint32(&tc, tokens[2]) ||
3094                         (tc > 0x7) ||
3095                         parser_read_uint32(&ttl, tokens[3]) ||
3096                         (ttl > 0x3F))
3097                         return 0;
3098
3099                 a->encap.mpls.mpls[1].label = label;
3100                 a->encap.mpls.mpls[1].tc = tc;
3101                 a->encap.mpls.mpls[1].ttl = ttl;
3102
3103                 tokens += 4;
3104                 n_tokens -= 4;
3105
3106                 if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
3107                         a->encap.mpls.mpls_count = 2;
3108                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3109                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3110                         return 1 + 8 + 4;
3111                 }
3112
3113                 if ((n_tokens < 4) ||
3114                         parser_read_uint32(&label, tokens[1]) ||
3115                         (label > 0xFFFFF) ||
3116                         parser_read_uint32(&tc, tokens[2]) ||
3117                         (tc > 0x7) ||
3118                         parser_read_uint32(&ttl, tokens[3]) ||
3119                         (ttl > 0x3F))
3120                         return 0;
3121
3122                 a->encap.mpls.mpls[2].label = label;
3123                 a->encap.mpls.mpls[2].tc = tc;
3124                 a->encap.mpls.mpls[2].ttl = ttl;
3125
3126                 tokens += 4;
3127                 n_tokens -= 4;
3128
3129                 if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
3130                         a->encap.mpls.mpls_count = 3;
3131                         a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3132                         a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3133                         return 1 + 8 + 4 + 4;
3134                 }
3135
3136                 if ((n_tokens < 4) ||
3137                         parser_read_uint32(&label, tokens[1]) ||
3138                         (label > 0xFFFFF) ||
3139                         parser_read_uint32(&tc, tokens[2]) ||
3140                         (tc > 0x7) ||
3141                         parser_read_uint32(&ttl, tokens[3]) ||
3142                         (ttl > 0x3F))
3143                         return 0;
3144
3145                 a->encap.mpls.mpls[3].label = label;
3146                 a->encap.mpls.mpls[3].tc = tc;
3147                 a->encap.mpls.mpls[3].ttl = ttl;
3148
3149                 a->encap.mpls.mpls_count = 4;
3150                 a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3151                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3152                 return 1 + 8 + 4 + 4 + 4;
3153         }
3154
3155         /* pppoe */
3156         if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3157                 if ((n_tokens < 4) ||
3158                         parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3159                         parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3160                         parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3161                                 tokens[3]))
3162                         return 0;
3163
3164                 a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3165                 a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3166                 return 1 + 4;
3167         }
3168
3169         return 0;
3170 }
3171
3172 static uint32_t
3173 parse_table_action_nat(char **tokens,
3174         uint32_t n_tokens,
3175         struct table_rule_action *a)
3176 {
3177         if ((n_tokens < 4) ||
3178                 strcmp(tokens[0], "nat"))
3179                 return 0;
3180
3181         if (strcmp(tokens[1], "ipv4") == 0) {
3182                 struct in_addr addr;
3183                 uint16_t port;
3184
3185                 if (parse_ipv4_addr(tokens[2], &addr) ||
3186                         parser_read_uint16(&port, tokens[3]))
3187                         return 0;
3188
3189                 a->nat.ip_version = 1;
3190                 a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3191                 a->nat.port = port;
3192                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3193                 return 4;
3194         }
3195
3196         if (strcmp(tokens[1], "ipv6") == 0) {
3197                 struct in6_addr addr;
3198                 uint16_t port;
3199
3200                 if (parse_ipv6_addr(tokens[2], &addr) ||
3201                         parser_read_uint16(&port, tokens[3]))
3202                         return 0;
3203
3204                 a->nat.ip_version = 0;
3205                 memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3206                 a->nat.port = port;
3207                 a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3208                 return 4;
3209         }
3210
3211         return 0;
3212 }
3213
3214 static uint32_t
3215 parse_table_action_ttl(char **tokens,
3216         uint32_t n_tokens,
3217         struct table_rule_action *a)
3218 {
3219         if ((n_tokens < 2) ||
3220                 strcmp(tokens[0], "ttl"))
3221                 return 0;
3222
3223         if (strcmp(tokens[1], "dec") == 0)
3224                 a->ttl.decrement = 1;
3225         else if (strcmp(tokens[1], "keep") == 0)
3226                 a->ttl.decrement = 0;
3227         else
3228                 return 0;
3229
3230         a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
3231         return 2;
3232 }
3233
3234 static uint32_t
3235 parse_table_action_stats(char **tokens,
3236         uint32_t n_tokens,
3237         struct table_rule_action *a)
3238 {
3239         if ((n_tokens < 1) ||
3240                 strcmp(tokens[0], "stats"))
3241                 return 0;
3242
3243         a->stats.n_packets = 0;
3244         a->stats.n_bytes = 0;
3245         a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
3246         return 1;
3247 }
3248
3249 static uint32_t
3250 parse_table_action_time(char **tokens,
3251         uint32_t n_tokens,
3252         struct table_rule_action *a)
3253 {
3254         if ((n_tokens < 1) ||
3255                 strcmp(tokens[0], "time"))
3256                 return 0;
3257
3258         a->time.time = rte_rdtsc();
3259         a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
3260         return 1;
3261 }
3262
3263 static uint32_t
3264 parse_table_action(char **tokens,
3265         uint32_t n_tokens,
3266         char *out,
3267         size_t out_size,
3268         struct table_rule_action *a)
3269 {
3270         uint32_t n_tokens0 = n_tokens;
3271
3272         memset(a, 0, sizeof(*a));
3273
3274         if ((n_tokens < 2) ||
3275                 strcmp(tokens[0], "action"))
3276                 return 0;
3277
3278         tokens++;
3279         n_tokens--;
3280
3281         if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
3282                 uint32_t n;
3283
3284                 n = parse_table_action_fwd(tokens, n_tokens, a);
3285                 if (n == 0) {
3286                         snprintf(out, out_size, MSG_ARG_INVALID,
3287                                 "action fwd");
3288                         return 0;
3289                 }
3290
3291                 tokens += n;
3292                 n_tokens -= n;
3293         }
3294
3295         if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
3296                 uint32_t n;
3297
3298                 n = parse_table_action_balance(tokens, n_tokens, a);
3299                 if (n == 0) {
3300                         snprintf(out, out_size, MSG_ARG_INVALID,
3301                                 "action balance");
3302                         return 0;
3303                 }
3304
3305                 tokens += n;
3306                 n_tokens -= n;
3307         }
3308
3309         if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
3310                 uint32_t n;
3311
3312                 n = parse_table_action_meter(tokens, n_tokens, a);
3313                 if (n == 0) {
3314                         snprintf(out, out_size, MSG_ARG_INVALID,
3315                                 "action meter");
3316                         return 0;
3317                 }
3318
3319                 tokens += n;
3320                 n_tokens -= n;
3321         }
3322
3323         if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
3324                 uint32_t n;
3325
3326                 n = parse_table_action_tm(tokens, n_tokens, a);
3327                 if (n == 0) {
3328                         snprintf(out, out_size, MSG_ARG_INVALID,
3329                                 "action tm");
3330                         return 0;
3331                 }
3332
3333                 tokens += n;
3334                 n_tokens -= n;
3335         }
3336
3337         if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
3338                 uint32_t n;
3339
3340                 n = parse_table_action_encap(tokens, n_tokens, a);
3341                 if (n == 0) {
3342                         snprintf(out, out_size, MSG_ARG_INVALID,
3343                                 "action encap");
3344                         return 0;
3345                 }
3346
3347                 tokens += n;
3348                 n_tokens -= n;
3349         }
3350
3351         if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
3352                 uint32_t n;
3353
3354                 n = parse_table_action_nat(tokens, n_tokens, a);
3355                 if (n == 0) {
3356                         snprintf(out, out_size, MSG_ARG_INVALID,
3357                                 "action nat");
3358                         return 0;
3359                 }
3360
3361                 tokens += n;
3362                 n_tokens -= n;
3363         }
3364
3365         if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
3366                 uint32_t n;
3367
3368                 n = parse_table_action_ttl(tokens, n_tokens, a);
3369                 if (n == 0) {
3370                         snprintf(out, out_size, MSG_ARG_INVALID,
3371                                 "action ttl");
3372                         return 0;
3373                 }
3374
3375                 tokens += n;
3376                 n_tokens -= n;
3377         }
3378
3379         if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
3380                 uint32_t n;
3381
3382                 n = parse_table_action_stats(tokens, n_tokens, a);
3383                 if (n == 0) {
3384                         snprintf(out, out_size, MSG_ARG_INVALID,
3385                                 "action stats");
3386                         return 0;
3387                 }
3388
3389                 tokens += n;
3390                 n_tokens -= n;
3391         }
3392
3393         if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
3394                 uint32_t n;
3395
3396                 n = parse_table_action_time(tokens, n_tokens, a);
3397                 if (n == 0) {
3398                         snprintf(out, out_size, MSG_ARG_INVALID,
3399                                 "action time");
3400                         return 0;
3401                 }
3402
3403                 tokens += n;
3404                 n_tokens -= n;
3405         }
3406
3407         if (n_tokens0 - n_tokens == 1) {
3408                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3409                 return 0;
3410         }
3411
3412         return n_tokens0 - n_tokens;
3413 }
3414
3415 /**
3416  * pipeline <pipeline_name> table <table_id> rule add
3417  *    match <match>
3418  *    action <table_action>
3419  */
3420 static void
3421 cmd_pipeline_table_rule_add(char **tokens,
3422         uint32_t n_tokens,
3423         char *out,
3424         size_t out_size)
3425 {
3426         struct table_rule_match m;
3427         struct table_rule_action a;
3428         char *pipeline_name;
3429         void *data;
3430         uint32_t table_id, t0, n_tokens_parsed;
3431         int status;
3432
3433         if (n_tokens < 8) {
3434                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3435                 return;
3436         }
3437
3438         pipeline_name = tokens[1];
3439
3440         if (strcmp(tokens[2], "table") != 0) {
3441                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3442                 return;
3443         }
3444
3445         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3446                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3447                 return;
3448         }
3449
3450         if (strcmp(tokens[4], "rule") != 0) {
3451                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3452                 return;
3453         }
3454
3455         if (strcmp(tokens[5], "add") != 0) {
3456                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3457                 return;
3458         }
3459
3460         t0 = 6;
3461
3462         /* match */
3463         n_tokens_parsed = parse_match(tokens + t0,
3464                 n_tokens - t0,
3465                 out,
3466                 out_size,
3467                 &m);
3468         if (n_tokens_parsed == 0)
3469                 return;
3470         t0 += n_tokens_parsed;
3471
3472         /* action */
3473         n_tokens_parsed = parse_table_action(tokens + t0,
3474                 n_tokens - t0,
3475                 out,
3476                 out_size,
3477                 &a);
3478         if (n_tokens_parsed == 0)
3479                 return;
3480         t0 += n_tokens_parsed;
3481
3482         if (t0 != n_tokens) {
3483                 snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
3484                 return;
3485         }
3486
3487         status = pipeline_table_rule_add(pipeline_name, table_id,
3488                 &m, &a, &data);
3489         if (status) {
3490                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3491                 return;
3492         }
3493 }
3494
3495 /**
3496  * pipeline <pipeline_name> table <table_id> rule add
3497  *    match
3498  *       default
3499  *    action
3500  *       fwd
3501  *          drop
3502  *          | port <port_id>
3503  *          | meta
3504  *          | table <table_id>
3505  */
3506 static void
3507 cmd_pipeline_table_rule_add_default(char **tokens,
3508         uint32_t n_tokens,
3509         char *out,
3510         size_t out_size)
3511 {
3512         struct table_rule_action action;
3513         void *data;
3514         char *pipeline_name;
3515         uint32_t table_id;
3516         int status;
3517
3518         if ((n_tokens != 11) && (n_tokens != 12)) {
3519                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3520                 return;
3521         }
3522
3523         pipeline_name = tokens[1];
3524
3525         if (strcmp(tokens[2], "table") != 0) {
3526                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3527                 return;
3528         }
3529
3530         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3531                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3532                 return;
3533         }
3534
3535         if (strcmp(tokens[4], "rule") != 0) {
3536                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3537                 return;
3538         }
3539
3540         if (strcmp(tokens[5], "add") != 0) {
3541                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3542                 return;
3543         }
3544
3545         if (strcmp(tokens[6], "match") != 0) {
3546                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3547                 return;
3548         }
3549
3550         if (strcmp(tokens[7], "default") != 0) {
3551                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3552                 return;
3553         }
3554
3555         if (strcmp(tokens[8], "action") != 0) {
3556                 snprintf(out, out_size, MSG_ARG_INVALID, "action");
3557                 return;
3558         }
3559
3560         if (strcmp(tokens[9], "fwd") != 0) {
3561                 snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
3562                 return;
3563         }
3564
3565         action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
3566
3567         if (strcmp(tokens[10], "drop") == 0) {
3568                 if (n_tokens != 11) {
3569                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3570                         return;
3571                 }
3572
3573                 action.fwd.action = RTE_PIPELINE_ACTION_DROP;
3574         } else if (strcmp(tokens[10], "port") == 0) {
3575                 uint32_t id;
3576
3577                 if (n_tokens != 12) {
3578                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3579                         return;
3580                 }
3581
3582                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3583                         snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
3584                         return;
3585                 }
3586
3587                 action.fwd.action = RTE_PIPELINE_ACTION_PORT;
3588                 action.fwd.id = id;
3589         } else if (strcmp(tokens[10], "meta") == 0) {
3590                 if (n_tokens != 11) {
3591                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3592                         return;
3593                 }
3594
3595                 action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3596         } else if (strcmp(tokens[10], "table") == 0) {
3597                 uint32_t id;
3598
3599                 if (n_tokens != 12) {
3600                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3601                         return;
3602                 }
3603
3604                 if (parser_read_uint32(&id, tokens[11]) != 0) {
3605                         snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3606                         return;
3607                 }
3608
3609                 action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
3610                 action.fwd.id = id;
3611         } else {
3612                 snprintf(out, out_size, MSG_ARG_INVALID,
3613                         "drop or port or meta or table");
3614                 return;
3615         }
3616
3617         status = pipeline_table_rule_add_default(pipeline_name,
3618                 table_id,
3619                 &action,
3620                 &data);
3621         if (status) {
3622                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3623                 return;
3624         }
3625 }
3626
3627 /**
3628  * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>
3629  *
3630  * File <file_name>:
3631  * - line format: match <match> action <action>
3632  */
3633 static int
3634 cli_rule_file_process(const char *file_name,
3635         size_t line_len_max,
3636         struct table_rule_match *m,
3637         struct table_rule_action *a,
3638         uint32_t *n_rules,
3639         uint32_t *line_number,
3640         char *out,
3641         size_t out_size);
3642
3643 static void
3644 cmd_pipeline_table_rule_add_bulk(char **tokens,
3645         uint32_t n_tokens,
3646         char *out,
3647         size_t out_size)
3648 {
3649         struct table_rule_match *match;
3650         struct table_rule_action *action;
3651         void **data;
3652         char *pipeline_name, *file_name;
3653         uint32_t table_id, n_rules, n_rules_parsed, line_number;
3654         int status;
3655
3656         if (n_tokens != 9) {
3657                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3658                 return;
3659         }
3660
3661         pipeline_name = tokens[1];
3662
3663         if (strcmp(tokens[2], "table") != 0) {
3664                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3665                 return;
3666         }
3667
3668         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3669                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3670                 return;
3671         }
3672
3673         if (strcmp(tokens[4], "rule") != 0) {
3674                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3675                 return;
3676         }
3677
3678         if (strcmp(tokens[5], "add") != 0) {
3679                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3680                 return;
3681         }
3682
3683         if (strcmp(tokens[6], "bulk") != 0) {
3684                 snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
3685                 return;
3686         }
3687
3688         file_name = tokens[7];
3689
3690         if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
3691                 (n_rules == 0)) {
3692                 snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
3693                 return;
3694         }
3695
3696         /* Memory allocation. */
3697         match = calloc(n_rules, sizeof(struct table_rule_match));
3698         action = calloc(n_rules, sizeof(struct table_rule_action));
3699         data = calloc(n_rules, sizeof(void *));
3700         if ((match == NULL) || (action == NULL) || (data == NULL)) {
3701                 snprintf(out, out_size, MSG_OUT_OF_MEMORY);
3702                 free(data);
3703                 free(action);
3704                 free(match);
3705                 return;
3706         }
3707
3708         /* Load rule file */
3709         n_rules_parsed = n_rules;
3710         status = cli_rule_file_process(file_name,
3711                 1024,
3712                 match,
3713                 action,
3714                 &n_rules_parsed,
3715                 &line_number,
3716                 out,
3717                 out_size);
3718         if (status) {
3719                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
3720                 free(data);
3721                 free(action);
3722                 free(match);
3723                 return;
3724         }
3725         if (n_rules_parsed != n_rules) {
3726                 snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
3727                 free(data);
3728                 free(action);
3729                 free(match);
3730                 return;
3731         }
3732
3733         /* Rule bulk add */
3734         status = pipeline_table_rule_add_bulk(pipeline_name,
3735                 table_id,
3736                 match,
3737                 action,
3738                 data,
3739                 &n_rules);
3740         if (status) {
3741                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3742                 free(data);
3743                 free(action);
3744                 free(match);
3745                 return;
3746         }
3747
3748         /* Memory free */
3749         free(data);
3750         free(action);
3751         free(match);
3752 }
3753
3754 /**
3755  * pipeline <pipeline_name> table <table_id> rule delete
3756  *    match <match>
3757  */
3758 static void
3759 cmd_pipeline_table_rule_delete(char **tokens,
3760         uint32_t n_tokens,
3761         char *out,
3762         size_t out_size)
3763 {
3764         struct table_rule_match m;
3765         char *pipeline_name;
3766         uint32_t table_id, n_tokens_parsed, t0;
3767         int status;
3768
3769         if (n_tokens < 8) {
3770                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3771                 return;
3772         }
3773
3774         pipeline_name = tokens[1];
3775
3776         if (strcmp(tokens[2], "table") != 0) {
3777                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3778                 return;
3779         }
3780
3781         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3782                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3783                 return;
3784         }
3785
3786         if (strcmp(tokens[4], "rule") != 0) {
3787                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3788                 return;
3789         }
3790
3791         if (strcmp(tokens[5], "delete") != 0) {
3792                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3793                 return;
3794         }
3795
3796         t0 = 6;
3797
3798         /* match */
3799         n_tokens_parsed = parse_match(tokens + t0,
3800                 n_tokens - t0,
3801                 out,
3802                 out_size,
3803                 &m);
3804         if (n_tokens_parsed == 0)
3805                 return;
3806         t0 += n_tokens_parsed;
3807
3808         if (n_tokens != t0) {
3809                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3810                 return;
3811         }
3812
3813         status = pipeline_table_rule_delete(pipeline_name,
3814                 table_id,
3815                 &m);
3816         if (status) {
3817                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3818                 return;
3819         }
3820 }
3821
3822 /**
3823  * pipeline <pipeline_name> table <table_id> rule delete
3824  *    match
3825  *       default
3826  */
3827 static void
3828 cmd_pipeline_table_rule_delete_default(char **tokens,
3829         uint32_t n_tokens,
3830         char *out,
3831         size_t out_size)
3832 {
3833         char *pipeline_name;
3834         uint32_t table_id;
3835         int status;
3836
3837         if (n_tokens != 8) {
3838                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3839                 return;
3840         }
3841
3842         pipeline_name = tokens[1];
3843
3844         if (strcmp(tokens[2], "table") != 0) {
3845                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
3846                 return;
3847         }
3848
3849         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3850                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3851                 return;
3852         }
3853
3854         if (strcmp(tokens[4], "rule") != 0) {
3855                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
3856                 return;
3857         }
3858
3859         if (strcmp(tokens[5], "delete") != 0) {
3860                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
3861                 return;
3862         }
3863
3864         if (strcmp(tokens[6], "match") != 0) {
3865                 snprintf(out, out_size, MSG_ARG_INVALID, "match");
3866                 return;
3867         }
3868
3869         if (strcmp(tokens[7], "default") != 0) {
3870                 snprintf(out, out_size, MSG_ARG_INVALID, "default");
3871                 return;
3872         }
3873
3874         status = pipeline_table_rule_delete_default(pipeline_name,
3875                 table_id);
3876         if (status) {
3877                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
3878                 return;
3879         }
3880 }
3881
3882 /**
3883  * pipeline <pipeline_name> table <table_id> rule read stats [clear]
3884  */
3885 static void
3886 cmd_pipeline_table_rule_stats_read(char **tokens,
3887         uint32_t n_tokens __rte_unused,
3888         char *out,
3889         size_t out_size)
3890 {
3891         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
3892 }
3893
3894 /**
3895  * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>
3896  *  add srtcm cir <cir> cbs <cbs> ebs <ebs>
3897  *  | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>
3898  */
3899 static void
3900 cmd_pipeline_table_meter_profile_add(char **tokens,
3901         uint32_t n_tokens,
3902         char *out,
3903         size_t out_size)
3904 {
3905         struct rte_table_action_meter_profile p;
3906         char *pipeline_name;
3907         uint32_t table_id, meter_profile_id;
3908         int status;
3909
3910         if (n_tokens < 9) {
3911                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3912                 return;
3913         }
3914
3915         pipeline_name = tokens[1];
3916
3917         if (strcmp(tokens[2], "table") != 0) {
3918                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
3919                 return;
3920         }
3921
3922         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
3923                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
3924                 return;
3925         }
3926
3927         if (strcmp(tokens[4], "meter") != 0) {
3928                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
3929                 return;
3930         }
3931
3932         if (strcmp(tokens[5], "profile") != 0) {
3933                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
3934                 return;
3935         }
3936
3937         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
3938                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
3939                 return;
3940         }
3941
3942         if (strcmp(tokens[7], "add") != 0) {
3943                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
3944                 return;
3945         }
3946
3947         if (strcmp(tokens[8], "srtcm") == 0) {
3948                 if (n_tokens != 15) {
3949                         snprintf(out, out_size, MSG_ARG_MISMATCH,
3950                                 tokens[0]);
3951                         return;
3952                 }
3953
3954                 p.alg = RTE_TABLE_ACTION_METER_SRTCM;
3955
3956                 if (strcmp(tokens[9], "cir") != 0) {
3957                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
3958                         return;
3959                 }
3960
3961                 if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
3962                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
3963                         return;
3964                 }
3965
3966                 if (strcmp(tokens[11], "cbs") != 0) {
3967                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
3968                         return;
3969                 }
3970
3971                 if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
3972                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
3973                         return;
3974                 }
3975
3976                 if (strcmp(tokens[13], "ebs") != 0) {
3977                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
3978                         return;
3979                 }
3980
3981                 if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
3982                         snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
3983                         return;
3984                 }
3985         } else if (strcmp(tokens[8], "trtcm") == 0) {
3986                 if (n_tokens != 17) {
3987                         snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3988                         return;
3989                 }
3990
3991                 p.alg = RTE_TABLE_ACTION_METER_TRTCM;
3992
3993                 if (strcmp(tokens[9], "cir") != 0) {
3994                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
3995                         return;
3996                 }
3997
3998                 if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
3999                         snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4000                         return;
4001                 }
4002
4003                 if (strcmp(tokens[11], "pir") != 0) {
4004                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
4005                         return;
4006                 }
4007
4008                 if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
4009                         snprintf(out, out_size, MSG_ARG_INVALID, "pir");
4010                         return;
4011                 }
4012                 if (strcmp(tokens[13], "cbs") != 0) {
4013                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4014                         return;
4015                 }
4016
4017                 if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
4018                         snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4019                         return;
4020                 }
4021
4022                 if (strcmp(tokens[15], "pbs") != 0) {
4023                         snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
4024                         return;
4025                 }
4026
4027                 if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
4028                         snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
4029                         return;
4030                 }
4031         } else {
4032                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4033                 return;
4034         }
4035
4036         status = pipeline_table_mtr_profile_add(pipeline_name,
4037                 table_id,
4038                 meter_profile_id,
4039                 &p);
4040         if (status) {
4041                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4042                 return;
4043         }
4044 }
4045
4046 /**
4047  * pipeline <pipeline_name> table <table_id>
4048  *  meter profile <meter_profile_id> delete
4049  */
4050 static void
4051 cmd_pipeline_table_meter_profile_delete(char **tokens,
4052         uint32_t n_tokens,
4053         char *out,
4054         size_t out_size)
4055 {
4056         char *pipeline_name;
4057         uint32_t table_id, meter_profile_id;
4058         int status;
4059
4060         if (n_tokens != 8) {
4061                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4062                 return;
4063         }
4064
4065         pipeline_name = tokens[1];
4066
4067         if (strcmp(tokens[2], "table") != 0) {
4068                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4069                 return;
4070         }
4071
4072         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4073                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4074                 return;
4075         }
4076
4077         if (strcmp(tokens[4], "meter") != 0) {
4078                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4079                 return;
4080         }
4081
4082         if (strcmp(tokens[5], "profile") != 0) {
4083                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4084                 return;
4085         }
4086
4087         if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4088                 snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4089                 return;
4090         }
4091
4092         if (strcmp(tokens[7], "delete") != 0) {
4093                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4094                 return;
4095         }
4096
4097         status = pipeline_table_mtr_profile_delete(pipeline_name,
4098                 table_id,
4099                 meter_profile_id);
4100         if (status) {
4101                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4102                 return;
4103         }
4104 }
4105
4106 /**
4107  * pipeline <pipeline_name> table <table_id> rule read meter [clear]
4108  */
4109 static void
4110 cmd_pipeline_table_rule_meter_read(char **tokens,
4111         uint32_t n_tokens __rte_unused,
4112         char *out,
4113         size_t out_size)
4114 {
4115         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4116 }
4117
4118 /**
4119  * pipeline <pipeline_name> table <table_id> dscp <file_name>
4120  *
4121  * File <file_name>:
4122  *  - exactly 64 lines
4123  *  - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r
4124  */
4125 static int
4126 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
4127         const char *file_name,
4128         uint32_t *line_number)
4129 {
4130         FILE *f = NULL;
4131         uint32_t dscp, l;
4132
4133         /* Check input arguments */
4134         if ((dscp_table == NULL) ||
4135                 (file_name == NULL) ||
4136                 (line_number == NULL)) {
4137                 if (line_number)
4138                         *line_number = 0;
4139                 return -EINVAL;
4140         }
4141
4142         /* Open input file */
4143         f = fopen(file_name, "r");
4144         if (f == NULL) {
4145                 *line_number = 0;
4146                 return -EINVAL;
4147         }
4148
4149         /* Read file */
4150         for (dscp = 0, l = 1; ; l++) {
4151                 char line[64];
4152                 char *tokens[3];
4153                 enum rte_meter_color color;
4154                 uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
4155
4156                 if (fgets(line, sizeof(line), f) == NULL)
4157                         break;
4158
4159                 if (is_comment(line))
4160                         continue;
4161
4162                 if (parse_tokenize_string(line, tokens, &n_tokens)) {
4163                         *line_number = l;
4164                         fclose(f);
4165                         return -EINVAL;
4166                 }
4167
4168                 if (n_tokens == 0)
4169                         continue;
4170
4171                 if ((dscp >= RTE_DIM(dscp_table->entry)) ||
4172                         (n_tokens != RTE_DIM(tokens)) ||
4173                         parser_read_uint32(&tc_id, tokens[0]) ||
4174                         (tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
4175                         parser_read_uint32(&tc_queue_id, tokens[1]) ||
4176                         (tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
4177                         (strlen(tokens[2]) != 1)) {
4178                         *line_number = l;
4179                         fclose(f);
4180                         return -EINVAL;
4181                 }
4182
4183                 switch (tokens[2][0]) {
4184                 case 'g':
4185                 case 'G':
4186                         color = e_RTE_METER_GREEN;
4187                         break;
4188
4189                 case 'y':
4190                 case 'Y':
4191                         color = e_RTE_METER_YELLOW;
4192                         break;
4193
4194                 case 'r':
4195                 case 'R':
4196                         color = e_RTE_METER_RED;
4197                         break;
4198
4199                 default:
4200                         *line_number = l;
4201                         fclose(f);
4202                         return -EINVAL;
4203                 }
4204
4205                 dscp_table->entry[dscp].tc_id = tc_id;
4206                 dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
4207                 dscp_table->entry[dscp].color = color;
4208                 dscp++;
4209         }
4210
4211         /* Close file */
4212         fclose(f);
4213         return 0;
4214 }
4215
4216 static void
4217 cmd_pipeline_table_dscp(char **tokens,
4218         uint32_t n_tokens,
4219         char *out,
4220         size_t out_size)
4221 {
4222         struct rte_table_action_dscp_table dscp_table;
4223         char *pipeline_name, *file_name;
4224         uint32_t table_id, line_number;
4225         int status;
4226
4227         if (n_tokens != 6) {
4228                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4229                 return;
4230         }
4231
4232         pipeline_name = tokens[1];
4233
4234         if (strcmp(tokens[2], "table") != 0) {
4235                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4236                 return;
4237         }
4238
4239         if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4240                 snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4241                 return;
4242         }
4243
4244         if (strcmp(tokens[4], "dscp") != 0) {
4245                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
4246                 return;
4247         }
4248
4249         file_name = tokens[5];
4250
4251         status = load_dscp_table(&dscp_table, file_name, &line_number);
4252         if (status) {
4253                 snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4254                 return;
4255         }
4256
4257         status = pipeline_table_dscp_table_update(pipeline_name,
4258                 table_id,
4259                 UINT64_MAX,
4260                 &dscp_table);
4261         if (status) {
4262                 snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4263                 return;
4264         }
4265 }
4266
4267 /**
4268  * pipeline <pipeline_name> table <table_id> rule read ttl [clear]
4269  */
4270 static void
4271 cmd_pipeline_table_rule_ttl_read(char **tokens,
4272         uint32_t n_tokens __rte_unused,
4273         char *out,
4274         size_t out_size)
4275 {
4276         snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4277 }
4278
4279 /**
4280  * thread <thread_id> pipeline <pipeline_name> enable
4281  */
4282 static void
4283 cmd_thread_pipeline_enable(char **tokens,
4284         uint32_t n_tokens,
4285         char *out,
4286         size_t out_size)
4287 {
4288         char *pipeline_name;
4289         uint32_t thread_id;
4290         int status;
4291
4292         if (n_tokens != 5) {
4293                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4294                 return;
4295         }
4296
4297         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4298                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4299                 return;
4300         }
4301
4302         if (strcmp(tokens[2], "pipeline") != 0) {
4303                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4304                 return;
4305         }
4306
4307         pipeline_name = tokens[3];
4308
4309         if (strcmp(tokens[4], "enable") != 0) {
4310                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
4311                 return;
4312         }
4313
4314         status = thread_pipeline_enable(thread_id, pipeline_name);
4315         if (status) {
4316                 snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
4317                 return;
4318         }
4319 }
4320
4321 /**
4322  * thread <thread_id> pipeline <pipeline_name> disable
4323  */
4324 static void
4325 cmd_thread_pipeline_disable(char **tokens,
4326         uint32_t n_tokens,
4327         char *out,
4328         size_t out_size)
4329 {
4330         char *pipeline_name;
4331         uint32_t thread_id;
4332         int status;
4333
4334         if (n_tokens != 5) {
4335                 snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4336                 return;
4337         }
4338
4339         if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
4340                 snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
4341                 return;
4342         }
4343
4344         if (strcmp(tokens[2], "pipeline") != 0) {
4345                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
4346                 return;
4347         }
4348
4349         pipeline_name = tokens[3];
4350
4351         if (strcmp(tokens[4], "disable") != 0) {
4352                 snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
4353                 return;
4354         }
4355
4356         status = thread_pipeline_disable(thread_id, pipeline_name);
4357         if (status) {
4358                 snprintf(out, out_size, MSG_CMD_FAIL,
4359                         "thread pipeline disable");
4360                 return;
4361         }
4362 }
4363
4364 void
4365 cli_process(char *in, char *out, size_t out_size)
4366 {
4367         char *tokens[CMD_MAX_TOKENS];
4368         uint32_t n_tokens = RTE_DIM(tokens);
4369         int status;
4370
4371         if (is_comment(in))
4372                 return;
4373
4374         status = parse_tokenize_string(in, tokens, &n_tokens);
4375         if (status) {
4376                 snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
4377                 return;
4378         }
4379
4380         if (n_tokens == 0)
4381                 return;
4382
4383         if (strcmp(tokens[0], "mempool") == 0) {
4384                 cmd_mempool(tokens, n_tokens, out, out_size);
4385                 return;
4386         }
4387
4388         if (strcmp(tokens[0], "link") == 0) {
4389                 cmd_link(tokens, n_tokens, out, out_size);
4390                 return;
4391         }
4392
4393         if (strcmp(tokens[0], "swq") == 0) {
4394                 cmd_swq(tokens, n_tokens, out, out_size);
4395                 return;
4396         }
4397
4398         if (strcmp(tokens[0], "tmgr") == 0) {
4399                 if ((n_tokens >= 3) &&
4400                         (strcmp(tokens[1], "subport") == 0) &&
4401                         (strcmp(tokens[2], "profile") == 0)) {
4402                         cmd_tmgr_subport_profile(tokens, n_tokens,
4403                                 out, out_size);
4404                         return;
4405                 }
4406
4407                 if ((n_tokens >= 3) &&
4408                         (strcmp(tokens[1], "pipe") == 0) &&
4409                         (strcmp(tokens[2], "profile") == 0)) {
4410                         cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
4411                         return;
4412                 }
4413
4414                 if ((n_tokens >= 5) &&
4415                         (strcmp(tokens[2], "subport") == 0) &&
4416                         (strcmp(tokens[4], "profile") == 0)) {
4417                         cmd_tmgr_subport(tokens, n_tokens, out, out_size);
4418                         return;
4419                 }
4420
4421                 if ((n_tokens >= 5) &&
4422                         (strcmp(tokens[2], "subport") == 0) &&
4423                         (strcmp(tokens[4], "pipe") == 0)) {
4424                         cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
4425                         return;
4426                 }
4427
4428                 cmd_tmgr(tokens, n_tokens, out, out_size);
4429                 return;
4430         }
4431
4432         if (strcmp(tokens[0], "tap") == 0) {
4433                 cmd_tap(tokens, n_tokens, out, out_size);
4434                 return;
4435         }
4436
4437         if (strcmp(tokens[0], "kni") == 0) {
4438                 cmd_kni(tokens, n_tokens, out, out_size);
4439                 return;
4440         }
4441
4442         if (strcmp(tokens[0], "port") == 0) {
4443                 cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
4444                 return;
4445         }
4446
4447         if (strcmp(tokens[0], "table") == 0) {
4448                 cmd_table_action_profile(tokens, n_tokens, out, out_size);
4449                 return;
4450         }
4451
4452         if (strcmp(tokens[0], "pipeline") == 0) {
4453                 if ((n_tokens >= 3) &&
4454                         (strcmp(tokens[2], "period") == 0)) {
4455                         cmd_pipeline(tokens, n_tokens, out, out_size);
4456                         return;
4457                 }
4458
4459                 if ((n_tokens >= 5) &&
4460                         (strcmp(tokens[2], "port") == 0) &&
4461                         (strcmp(tokens[3], "in") == 0) &&
4462                         (strcmp(tokens[4], "bsz") == 0)) {
4463                         cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
4464                         return;
4465                 }
4466
4467                 if ((n_tokens >= 5) &&
4468                         (strcmp(tokens[2], "port") == 0) &&
4469                         (strcmp(tokens[3], "out") == 0) &&
4470                         (strcmp(tokens[4], "bsz") == 0)) {
4471                         cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
4472                         return;
4473                 }
4474
4475                 if ((n_tokens >= 4) &&
4476                         (strcmp(tokens[2], "table") == 0) &&
4477                         (strcmp(tokens[3], "match") == 0)) {
4478                         cmd_pipeline_table(tokens, n_tokens, out, out_size);
4479                         return;
4480                 }
4481
4482                 if ((n_tokens >= 6) &&
4483                         (strcmp(tokens[2], "port") == 0) &&
4484                         (strcmp(tokens[3], "in") == 0) &&
4485                         (strcmp(tokens[5], "table") == 0)) {
4486                         cmd_pipeline_port_in_table(tokens, n_tokens,
4487                                 out, out_size);
4488                         return;
4489                 }
4490
4491                 if ((n_tokens >= 6) &&
4492                         (strcmp(tokens[2], "port") == 0) &&
4493                         (strcmp(tokens[3], "in") == 0) &&
4494                         (strcmp(tokens[5], "stats") == 0)) {
4495                         cmd_pipeline_port_in_stats(tokens, n_tokens,
4496                                 out, out_size);
4497                         return;
4498                 }
4499
4500                 if ((n_tokens >= 6) &&
4501                         (strcmp(tokens[2], "port") == 0) &&
4502                         (strcmp(tokens[3], "in") == 0) &&
4503                         (strcmp(tokens[5], "enable") == 0)) {
4504                         cmd_pipeline_port_in_enable(tokens, n_tokens,
4505                                 out, out_size);
4506                         return;
4507                 }
4508
4509                 if ((n_tokens >= 6) &&
4510                         (strcmp(tokens[2], "port") == 0) &&
4511                         (strcmp(tokens[3], "in") == 0) &&
4512                         (strcmp(tokens[5], "disable") == 0)) {
4513                         cmd_pipeline_port_in_disable(tokens, n_tokens,
4514                                 out, out_size);
4515                         return;
4516                 }
4517
4518                 if ((n_tokens >= 6) &&
4519                         (strcmp(tokens[2], "port") == 0) &&
4520                         (strcmp(tokens[3], "out") == 0) &&
4521                         (strcmp(tokens[5], "stats") == 0)) {
4522                         cmd_pipeline_port_out_stats(tokens, n_tokens,
4523                                 out, out_size);
4524                         return;
4525                 }
4526
4527                 if ((n_tokens >= 5) &&
4528                         (strcmp(tokens[2], "table") == 0) &&
4529                         (strcmp(tokens[4], "stats") == 0)) {
4530                         cmd_pipeline_table_stats(tokens, n_tokens,
4531                                 out, out_size);
4532                         return;
4533                 }
4534
4535                 if ((n_tokens >= 7) &&
4536                         (strcmp(tokens[2], "table") == 0) &&
4537                         (strcmp(tokens[4], "rule") == 0) &&
4538                         (strcmp(tokens[5], "add") == 0) &&
4539                         (strcmp(tokens[6], "match") == 0)) {
4540                         if ((n_tokens >= 8) &&
4541                                 (strcmp(tokens[7], "default") == 0)) {
4542                                 cmd_pipeline_table_rule_add_default(tokens,
4543                                         n_tokens, out, out_size);
4544                                 return;
4545                         }
4546
4547                         cmd_pipeline_table_rule_add(tokens, n_tokens,
4548                                 out, out_size);
4549                         return;
4550                 }
4551
4552                 if ((n_tokens >= 7) &&
4553                         (strcmp(tokens[2], "table") == 0) &&
4554                         (strcmp(tokens[4], "rule") == 0) &&
4555                         (strcmp(tokens[5], "add") == 0) &&
4556                         (strcmp(tokens[6], "bulk") == 0)) {
4557                         cmd_pipeline_table_rule_add_bulk(tokens,
4558                                 n_tokens, out, out_size);
4559                         return;
4560                 }
4561
4562                 if ((n_tokens >= 7) &&
4563                         (strcmp(tokens[2], "table") == 0) &&
4564                         (strcmp(tokens[4], "rule") == 0) &&
4565                         (strcmp(tokens[5], "delete") == 0) &&
4566                         (strcmp(tokens[6], "match") == 0)) {
4567                         if ((n_tokens >= 8) &&
4568                                 (strcmp(tokens[7], "default") == 0)) {
4569                                 cmd_pipeline_table_rule_delete_default(tokens,
4570                                         n_tokens, out, out_size);
4571                                 return;
4572                                 }
4573
4574                         cmd_pipeline_table_rule_delete(tokens, n_tokens,
4575                                 out, out_size);
4576                         return;
4577                 }
4578
4579                 if ((n_tokens >= 7) &&
4580                         (strcmp(tokens[2], "table") == 0) &&
4581                         (strcmp(tokens[4], "rule") == 0) &&
4582                         (strcmp(tokens[5], "read") == 0) &&
4583                         (strcmp(tokens[6], "stats") == 0)) {
4584                         cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
4585                                 out, out_size);
4586                         return;
4587                 }
4588
4589                 if ((n_tokens >= 8) &&
4590                         (strcmp(tokens[2], "table") == 0) &&
4591                         (strcmp(tokens[4], "meter") == 0) &&
4592                         (strcmp(tokens[5], "profile") == 0) &&
4593                         (strcmp(tokens[7], "add") == 0)) {
4594                         cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
4595                                 out, out_size);
4596                         return;
4597                 }
4598
4599                 if ((n_tokens >= 8) &&
4600                         (strcmp(tokens[2], "table") == 0) &&
4601                         (strcmp(tokens[4], "meter") == 0) &&
4602                         (strcmp(tokens[5], "profile") == 0) &&
4603                         (strcmp(tokens[7], "delete") == 0)) {
4604                         cmd_pipeline_table_meter_profile_delete(tokens,
4605                                 n_tokens, out, out_size);
4606                         return;
4607                 }
4608
4609                 if ((n_tokens >= 7) &&
4610                         (strcmp(tokens[2], "table") == 0) &&
4611                         (strcmp(tokens[4], "rule") == 0) &&
4612                         (strcmp(tokens[5], "read") == 0) &&
4613                         (strcmp(tokens[6], "meter") == 0)) {
4614                         cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
4615                                 out, out_size);
4616                         return;
4617                 }
4618
4619                 if ((n_tokens >= 5) &&
4620                         (strcmp(tokens[2], "table") == 0) &&
4621                         (strcmp(tokens[4], "dscp") == 0)) {
4622                         cmd_pipeline_table_dscp(tokens, n_tokens,
4623                                 out, out_size);
4624                         return;
4625                 }
4626
4627                 if ((n_tokens >= 7) &&
4628                         (strcmp(tokens[2], "table") == 0) &&
4629                         (strcmp(tokens[4], "rule") == 0) &&
4630                         (strcmp(tokens[5], "read") == 0) &&
4631                         (strcmp(tokens[6], "ttl") == 0)) {
4632                         cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
4633                                 out, out_size);
4634                         return;
4635                 }
4636         }
4637
4638         if (strcmp(tokens[0], "thread") == 0) {
4639                 if ((n_tokens >= 5) &&
4640                         (strcmp(tokens[4], "enable") == 0)) {
4641                         cmd_thread_pipeline_enable(tokens, n_tokens,
4642                                 out, out_size);
4643                         return;
4644                 }
4645
4646                 if ((n_tokens >= 5) &&
4647                         (strcmp(tokens[4], "disable") == 0)) {
4648                         cmd_thread_pipeline_disable(tokens, n_tokens,
4649                                 out, out_size);
4650                         return;
4651                 }
4652         }
4653
4654         snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
4655 }
4656
4657 int
4658 cli_script_process(const char *file_name,
4659         size_t msg_in_len_max,
4660         size_t msg_out_len_max)
4661 {
4662         char *msg_in = NULL, *msg_out = NULL;
4663         FILE *f = NULL;
4664
4665         /* Check input arguments */
4666         if ((file_name == NULL) ||
4667                 (strlen(file_name) == 0) ||
4668                 (msg_in_len_max == 0) ||
4669                 (msg_out_len_max == 0))
4670                 return -EINVAL;
4671
4672         msg_in = malloc(msg_in_len_max + 1);
4673         msg_out = malloc(msg_out_len_max + 1);
4674         if ((msg_in == NULL) ||
4675                 (msg_out == NULL)) {
4676                 free(msg_out);
4677                 free(msg_in);
4678                 return -ENOMEM;
4679         }
4680
4681         /* Open input file */
4682         f = fopen(file_name, "r");
4683         if (f == NULL) {
4684                 free(msg_out);
4685                 free(msg_in);
4686                 return -EIO;
4687         }
4688
4689         /* Read file */
4690         for ( ; ; ) {
4691                 if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
4692                         break;
4693
4694                 printf("%s", msg_in);
4695                 msg_out[0] = 0;
4696
4697                 cli_process(msg_in,
4698                         msg_out,
4699                         msg_out_len_max);
4700
4701                 if (strlen(msg_out))
4702                         printf("%s", msg_out);
4703         }
4704
4705         /* Close file */
4706         fclose(f);
4707         free(msg_out);
4708         free(msg_in);
4709         return 0;
4710 }
4711
4712 static int
4713 cli_rule_file_process(const char *file_name,
4714         size_t line_len_max,
4715         struct table_rule_match *m,
4716         struct table_rule_action *a,
4717         uint32_t *n_rules,
4718         uint32_t *line_number,
4719         char *out,
4720         size_t out_size)
4721 {
4722         FILE *f = NULL;
4723         char *line = NULL;
4724         uint32_t rule_id, line_id;
4725         int status = 0;
4726
4727         /* Check input arguments */
4728         if ((file_name == NULL) ||
4729                 (strlen(file_name) == 0) ||
4730                 (line_len_max == 0)) {
4731                 *line_number = 0;
4732                 return -EINVAL;
4733         }
4734
4735         /* Memory allocation */
4736         line = malloc(line_len_max + 1);
4737         if (line == NULL) {
4738                 *line_number = 0;
4739                 return -ENOMEM;
4740         }
4741
4742         /* Open file */
4743         f = fopen(file_name, "r");
4744         if (f == NULL) {
4745                 *line_number = 0;
4746                 free(line);
4747                 return -EIO;
4748         }
4749
4750         /* Read file */
4751         for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
4752                 char *tokens[CMD_MAX_TOKENS];
4753                 uint32_t n_tokens, n_tokens_parsed, t0;
4754
4755                 /* Read next line from file. */
4756                 if (fgets(line, line_len_max + 1, f) == NULL)
4757                         break;
4758
4759                 /* Comment. */
4760                 if (is_comment(line))
4761                         continue;
4762
4763                 /* Parse line. */
4764                 n_tokens = RTE_DIM(tokens);
4765                 status = parse_tokenize_string(line, tokens, &n_tokens);
4766                 if (status) {
4767                         status = -EINVAL;
4768                         break;
4769                 }
4770
4771                 /* Empty line. */
4772                 if (n_tokens == 0)
4773                         continue;
4774                 t0 = 0;
4775
4776                 /* Rule match. */
4777                 n_tokens_parsed = parse_match(tokens + t0,
4778                         n_tokens - t0,
4779                         out,
4780                         out_size,
4781                         &m[rule_id]);
4782                 if (n_tokens_parsed == 0) {
4783                         status = -EINVAL;
4784                         break;
4785                 }
4786                 t0 += n_tokens_parsed;
4787
4788                 /* Rule action. */
4789                 n_tokens_parsed = parse_table_action(tokens + t0,
4790                         n_tokens - t0,
4791                         out,
4792                         out_size,
4793                         &a[rule_id]);
4794                 if (n_tokens_parsed == 0) {
4795                         status = -EINVAL;
4796                         break;
4797                 }
4798                 t0 += n_tokens_parsed;
4799
4800                 /* Line completed. */
4801                 if (t0 < n_tokens) {
4802                         status = -EINVAL;
4803                         break;
4804                 }
4805
4806                 /* Increment rule count */
4807                 rule_id++;
4808         }
4809
4810         /* Close file */
4811         fclose(f);
4812
4813         /* Memory free */
4814         free(line);
4815
4816         *n_rules = rule_id;
4817         *line_number = line_id;
4818         return status;
4819 }