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